diff --git a/docs/changes.txt b/docs/changes.txt index b9ae88a031..84e9f3c69f 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -155,6 +155,9 @@ All (GUI): in wxPGArrayEditorDialog. - Fix wxPropertyGrid issues with horizontal scrolling. - Add wxPG_DIALOG_TITLE wxPGProperty attribute. +- Add support for creating a wxGraphicsPen with a gradient. +- Add support for applying a transformation matrix to a gradient. + wxGTK: diff --git a/include/wx/graphics.h b/include/wx/graphics.h index 86a4444fb0..059d11c62d 100644 --- a/include/wx/graphics.h +++ b/include/wx/graphics.h @@ -71,6 +71,14 @@ enum wxCompositionMode wxCOMPOSITION_ADD /* R = S + D */ }; +enum wxGradientType +{ + wxGRADIENT_NONE, + wxGRADIENT_LINEAR, + wxGRADIENT_RADIAL +}; + + class WXDLLIMPEXP_FWD_CORE wxDC; class WXDLLIMPEXP_FWD_CORE wxWindowDC; class WXDLLIMPEXP_FWD_CORE wxMemoryDC; @@ -92,6 +100,7 @@ class WXDLLIMPEXP_FWD_CORE wxGraphicsBrush; class WXDLLIMPEXP_FWD_CORE wxGraphicsFont; class WXDLLIMPEXP_FWD_CORE wxGraphicsBitmap; + /* * notes about the graphics context apis * @@ -133,33 +142,7 @@ protected: wxDECLARE_DYNAMIC_CLASS(wxGraphicsObject); }; -// ---------------------------------------------------------------------------- -// wxGraphicsPenInfo describes a wxGraphicsPen -// ---------------------------------------------------------------------------- -class wxGraphicsPenInfo : public wxPenInfoBase -{ -public: - explicit wxGraphicsPenInfo(const wxColour& colour = wxColour(), - wxDouble width = 1.0, - wxPenStyle style = wxPENSTYLE_SOLID) - : wxPenInfoBase(colour, style) - { - m_width = width; - } - - // Setters - - wxGraphicsPenInfo& Width(wxDouble width) - { m_width = width; return *this; } - - // Accessors - - wxDouble GetWidth() const { return m_width; } - -private: - wxDouble m_width; -}; class WXDLLIMPEXP_CORE wxGraphicsPen : public wxGraphicsObject { @@ -286,6 +269,201 @@ private: extern WXDLLIMPEXP_DATA_CORE(wxGraphicsMatrix) wxNullGraphicsMatrix; +// ---------------------------------------------------------------------------- +// wxGradientStop and wxGradientStops: Specify what intermediate colors are used +// and how they are spread out in a gradient +// ---------------------------------------------------------------------------- + +// Describes a single gradient stop. +class wxGraphicsGradientStop +{ +public: + wxGraphicsGradientStop(wxColour col = wxTransparentColour, + float pos = 0.) + : m_col(col), + m_pos(pos) + { + } + + // default copy ctor, assignment operator and dtor are ok + + const wxColour& GetColour() const { return m_col; } + void SetColour(const wxColour& col) { m_col = col; } + + float GetPosition() const { return m_pos; } + void SetPosition(float pos) + { + wxASSERT_MSG( pos >= 0 && pos <= 1, "invalid gradient stop position" ); + + m_pos = pos; + } + +private: + // The colour of this gradient band. + wxColour m_col; + + // Its starting position: 0 is the beginning and 1 is the end. + float m_pos; +}; + +// A collection of gradient stops ordered by their positions (from lowest to +// highest). The first stop (index 0, position 0.0) is always the starting +// colour and the last one (index GetCount() - 1, position 1.0) is the end +// colour. +class WXDLLIMPEXP_CORE wxGraphicsGradientStops +{ +public: + wxGraphicsGradientStops(wxColour startCol = wxTransparentColour, + wxColour endCol = wxTransparentColour) + { + // we can't use Add() here as it relies on having start/end stops as + // first/last array elements so do it manually + m_stops.push_back(wxGraphicsGradientStop(startCol, 0.f)); + m_stops.push_back(wxGraphicsGradientStop(endCol, 1.f)); + } + + // default copy ctor, assignment operator and dtor are ok for this class + + + // Add a stop in correct order. + void Add(const wxGraphicsGradientStop& stop); + void Add(wxColour col, float pos) { Add(wxGraphicsGradientStop(col, pos)); } + + // Get the number of stops. + size_t GetCount() const { return m_stops.size(); } + + // Return the stop at the given index (which must be valid). + wxGraphicsGradientStop Item(unsigned n) const { return m_stops.at(n); } + + // Get/set start and end colours. + void SetStartColour(wxColour col) + { m_stops[0].SetColour(col); } + wxColour GetStartColour() const + { return m_stops[0].GetColour(); } + void SetEndColour(wxColour col) + { m_stops[m_stops.size() - 1].SetColour(col); } + wxColour GetEndColour() const + { return m_stops[m_stops.size() - 1].GetColour(); } + +private: + // All the stops stored in ascending order of positions. + wxVector m_stops; +}; + +// ---------------------------------------------------------------------------- +// wxGraphicsPenInfo describes a wxGraphicsPen +// ---------------------------------------------------------------------------- + +class wxGraphicsPenInfo : public wxPenInfoBase +{ +public: + explicit wxGraphicsPenInfo(const wxColour& colour = wxColour(), + wxDouble width = 1.0, + wxPenStyle style = wxPENSTYLE_SOLID) + : wxPenInfoBase(colour, style) + { + m_width = width; + m_gradientType = wxGRADIENT_NONE; + } + + // Setters + + wxGraphicsPenInfo& Width(wxDouble width) + { m_width = width; return *this; } + + wxGraphicsPenInfo& + LinearGradient(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + const wxColour& c1, const wxColour& c2, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) + { + m_gradientType = wxGRADIENT_LINEAR; + m_x1 = x1; + m_y1 = y1; + m_x2 = x2; + m_y2 = y2; + m_stops.SetStartColour(c1); + m_stops.SetEndColour(c2); + m_matrix = matrix; + return *this; + } + + wxGraphicsPenInfo& + LinearGradient(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) + { + m_gradientType = wxGRADIENT_LINEAR; + m_x1 = x1; + m_y1 = y1; + m_x2 = x2; + m_y2 = y2; + m_stops = stops; + m_matrix = matrix; + return *this; + } + + wxGraphicsPenInfo& + RadialGradient(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, + const wxColour& oColor, const wxColour& cColor, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) + { + m_gradientType = wxGRADIENT_RADIAL; + m_x1 = startX; + m_y1 = startY; + m_x2 = endX; + m_y2 = endY; + m_radius = radius; + m_stops.SetStartColour(oColor); + m_stops.SetEndColour(cColor); + m_matrix = matrix; + return *this; + } + + wxGraphicsPenInfo& + RadialGradient(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, + wxDouble radius, const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) + { + m_gradientType = wxGRADIENT_RADIAL; + m_x1 = startX; + m_y1 = startY; + m_x2 = endX; + m_y2 = endY; + m_radius = radius; + m_stops = stops; + m_matrix = matrix; + return *this; + } + + // Accessors + + wxDouble GetWidth() const { return m_width; } + wxGradientType GetGradientType() const { return m_gradientType; } + wxDouble GetX1() const { return m_x1; } + wxDouble GetY1() const { return m_y1; } + wxDouble GetX2() const { return m_x2; } + wxDouble GetY2() const { return m_y2; } + wxDouble GetStartX() const { return m_x1; } + wxDouble GetStartY() const { return m_y1; } + wxDouble GetEndX() const { return m_x2; } + wxDouble GetEndY() const { return m_y2; } + wxDouble GetRadius() const { return m_radius; } + const wxGraphicsGradientStops& GetStops() const { return m_stops; } + const wxGraphicsMatrix& GetMatrix() const { return m_matrix; } + +private: + wxDouble m_width; + wxGradientType m_gradientType; + wxDouble m_x1, m_y1, m_x2, m_y2; // also used for m_xo, m_yo, m_xc, m_yc + wxDouble m_radius; + wxGraphicsGradientStops m_stops; + wxGraphicsMatrix m_matrix; +}; + + + class WXDLLIMPEXP_CORE wxGraphicsPath : public wxGraphicsObject { public: @@ -373,82 +551,6 @@ private: extern WXDLLIMPEXP_DATA_CORE(wxGraphicsPath) wxNullGraphicsPath; -// Describes a single gradient stop. -class wxGraphicsGradientStop -{ -public: - wxGraphicsGradientStop(wxColour col = wxTransparentColour, - float pos = 0.) - : m_col(col), - m_pos(pos) - { - } - - // default copy ctor, assignment operator and dtor are ok - - const wxColour& GetColour() const { return m_col; } - void SetColour(const wxColour& col) { m_col = col; } - - float GetPosition() const { return m_pos; } - void SetPosition(float pos) - { - wxASSERT_MSG( pos >= 0 && pos <= 1, "invalid gradient stop position" ); - - m_pos = pos; - } - -private: - // The colour of this gradient band. - wxColour m_col; - - // Its starting position: 0 is the beginning and 1 is the end. - float m_pos; -}; - -// A collection of gradient stops ordered by their positions (from lowest to -// highest). The first stop (index 0, position 0.0) is always the starting -// colour and the last one (index GetCount() - 1, position 1.0) is the end -// colour. -class WXDLLIMPEXP_CORE wxGraphicsGradientStops -{ -public: - wxGraphicsGradientStops(wxColour startCol = wxTransparentColour, - wxColour endCol = wxTransparentColour) - { - // we can't use Add() here as it relies on having start/end stops as - // first/last array elements so do it manually - m_stops.push_back(wxGraphicsGradientStop(startCol, 0.f)); - m_stops.push_back(wxGraphicsGradientStop(endCol, 1.f)); - } - - // default copy ctor, assignment operator and dtor are ok for this class - - - // Add a stop in correct order. - void Add(const wxGraphicsGradientStop& stop); - void Add(wxColour col, float pos) { Add(wxGraphicsGradientStop(col, pos)); } - - // Get the number of stops. - size_t GetCount() const { return m_stops.size(); } - - // Return the stop at the given index (which must be valid). - wxGraphicsGradientStop Item(unsigned n) const { return m_stops.at(n); } - - // Get/set start and end colours. - void SetStartColour(wxColour col) - { m_stops[0].SetColour(col); } - wxColour GetStartColour() const - { return m_stops[0].GetColour(); } - void SetEndColour(wxColour col) - { m_stops[m_stops.size() - 1].SetColour(col); } - wxColour GetEndColour() const - { return m_stops[m_stops.size() - 1].GetColour(); } - -private: - // All the stops stored in ascending order of positions. - wxVector m_stops; -}; - class WXDLLIMPEXP_CORE wxGraphicsContext : public wxGraphicsObject { public: @@ -523,24 +625,28 @@ public: wxGraphicsBrush CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour& c1, const wxColour& c2) const; + const wxColour& c1, const wxColour& c2, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) const; wxGraphicsBrush CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) const; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) const; // sets the brush to a radial gradient originating at (xo,yc) and ending // on a circle around (xc,yc) with the given radius; the colours may be // specified by just the two extremes or the full array of gradient stops wxGraphicsBrush - CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour& oColor, const wxColour& cColor) const; + CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, + const wxColour& oColor, const wxColour& cColor, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) const; wxGraphicsBrush - CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, wxDouble radius, - const wxGraphicsGradientStops& stops) const; + CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) const; // creates a font virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) const; @@ -916,13 +1022,15 @@ public: virtual wxGraphicsBrush CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) = 0; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) = 0; virtual wxGraphicsBrush - CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, + CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, - const wxGraphicsGradientStops& stops) = 0; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) = 0; // sets the font virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) = 0; diff --git a/interface/wx/graphics.h b/interface/wx/graphics.h index 95720f0113..7e09c7d6ee 100644 --- a/interface/wx/graphics.h +++ b/interface/wx/graphics.h @@ -305,6 +305,19 @@ enum wxCompositionMode wxCOMPOSITION_ADD /**< @e R = @e S + @e D */ }; +/** + Used to indicate what kind of gradient is set in a wxGraphicsPenInfo + object. + + @since 3.1.3 + */ +enum wxGradientType { + wxGRADIENT_NONE, + wxGRADIENT_LINEAR, + wxGRADIENT_RADIAL +}; + + /** Represents a bitmap. @@ -633,11 +646,14 @@ public: of gradient @a stops can be specified. The version taking wxGraphicsGradientStops is new in wxWidgets 2.9.1. + + The @a matrix parameter was added in wxWidgets 3.1.3 */ wxGraphicsBrush CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour& c1, const wxColour& c2) const; + const wxColour& c1, const wxColour& c2, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) const; /** @overload @@ -645,34 +661,39 @@ public: wxGraphicsBrush CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) const; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) const; /** Creates a native brush with a radial gradient. - The brush originates at (@a xo, @a yc) and ends on a circle around - (@a xc, @a yc) with the given @a radius. + The brush originates at (@a startX, @a startY) and ends on a circle around + (@a endX, @a endY) with the given @a radius. The gradient may be specified either by its start and end colours @a oColor and @a cColor or by a full set of gradient @a stops. The version taking wxGraphicsGradientStops is new in wxWidgets 2.9.1. + + The ability to apply a transformation matrix to the gradient was added in 3.1.3 */ virtual wxGraphicsBrush - CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, + CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, const wxColour& oColor, - const wxColour& cColor) const; + const wxColour& cColor, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) const; /** @overload */ virtual wxGraphicsBrush - CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, + CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, - const wxGraphicsGradientStops& stops) = 0; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) = 0; /** Sets the brush for filling paths. @@ -1444,12 +1465,16 @@ public: Stops support is new since wxWidgets 2.9.1, previously only the start and end colours could be specified. + + The ability to apply a transformation matrix to the gradient was added in 3.1.3 + */ virtual wxGraphicsBrush CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) = 0; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) = 0; /** Creates a native affine transformation matrix from the passed in @@ -1477,11 +1502,14 @@ public: Stops support is new since wxWidgets 2.9.1, previously only the start and end colours could be specified. + + The ability to apply a transformation matrix to the gradient was added in 3.1.3 */ - virtual wxGraphicsBrush CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, + virtual wxGraphicsBrush CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, - const wxGraphicsGradientStops& stops) = 0; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) = 0; /** Extracts a sub-bitmap from an existing bitmap. @@ -1620,6 +1648,50 @@ public: wxGraphicsPenInfo& Join(wxPenJoin join); wxGraphicsPenInfo& Cap(wxPenCap cap); + + wxGraphicsPenInfo& + LinearGradient(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + const wxColour& c1, const wxColour& c2, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix); + + wxGraphicsPenInfo& + LinearGradient(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix); + + wxGraphicsPenInfo& + RadialGradient(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, + const wxColour& oColor, const wxColour& cColor, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix); + + wxGraphicsPenInfo& + RadialGradient(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, + wxDouble radius, const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix); + + wxColour GetColour() const; + wxBitmap GetStipple() const; + wxPenStyle GetStyle() const; + wxPenJoin GetJoin() const; + wxPenCap GetCap() const; + int GetDashes(wxDash **ptr); + int GetDashCount() const; + wxDash* GetDash() const; + bool IsTransparent() const; + wxDouble GetWidth() const; + wxGradientType GetGradientType() const; + wxDouble GetX1() const; + wxDouble GetY1() const; + wxDouble GetX2() const; + wxDouble GetY2() const; + wxDouble GetStartX() const; + wxDouble GetStartY() const; + wxDouble GetEndX() const; + wxDouble GetEndY() const; + wxDouble GetRadius() const; + const wxGraphicsGradientStops& GetStops() const; }; diff --git a/interface/wx/pen.h b/interface/wx/pen.h index d6df1c3f4d..ceeab7ad9e 100644 --- a/interface/wx/pen.h +++ b/interface/wx/pen.h @@ -137,6 +137,17 @@ public: wxPenInfo& Join(wxPenJoin join); wxPenInfo& Cap(wxPenCap cap); + + wxColour GetColour() const; + wxBitmap GetStipple() const; + wxPenStyle GetStyle() const; + wxPenJoin GetJoin() const; + wxPenCap GetCap() const; + int GetDashes(wxDash **ptr); + int GetDashCount() const; + wxDash* GetDash() const; + bool IsTransparent() const; + int GetWidth() const; }; diff --git a/samples/drawing/drawing.cpp b/samples/drawing/drawing.cpp index d9cb0dfa8d..2ec40a6229 100644 --- a/samples/drawing/drawing.cpp +++ b/samples/drawing/drawing.cpp @@ -1638,6 +1638,29 @@ void MyCanvas::DrawGradients(wxDC& dc) pth.GetBox(&boxX, &boxY, &boxWidth, &boxHeight); dc.CalcBoundingBox(wxRound(boxX), wxRound(boxY)); dc.CalcBoundingBox(wxRound(boxX+boxWidth), wxRound(boxY+boxHeight)); + + gfr.Offset(0, gfr.height + 10); + dc.DrawText("Stroked path with a gradient pen", gfr.x, gfr.y); + gfr.Offset(0, TEXT_HEIGHT); + + pth = gc->CreatePath(); + pth.MoveToPoint(gfr.x + gfr.width/2, gfr.y); + pth.AddLineToPoint(gfr.x + gfr.width, gfr.y + gfr.height/2); + pth.AddLineToPoint(gfr.x + gfr.width/2, gfr.y + gfr.height); + pth.AddLineToPoint(gfr.x, gfr.y + gfr.height/2); + pth.CloseSubpath(); + + stops = wxGraphicsGradientStops(*wxRED, *wxBLUE); + stops.Add(wxColour(255,255,0), 0.33f); + stops.Add(*wxGREEN, 0.67f); + + wxGraphicsPen pen = gc->CreatePen( + wxGraphicsPenInfo(wxColour(0,0,0)).Width(6).Join(wxJOIN_BEVEL).LinearGradient( + gfr.x + gfr.width/2, gfr.y, + gfr.x + gfr.width/2, gfr.y + gfr.height, + stops)); + gc->SetPen(pen); + gc->StrokePath(pth); } #endif // wxUSE_GRAPHICS_CONTEXT } diff --git a/src/common/cairo.cpp b/src/common/cairo.cpp index 3b86f79192..7b29ef4065 100644 --- a/src/common/cairo.cpp +++ b/src/common/cairo.cpp @@ -110,6 +110,8 @@ (cairo_pattern_t *pattern, cairo_extend_t extend), (pattern, extend) ) \ m( cairo_pattern_set_filter, \ (cairo_pattern_t *pattern, cairo_filter_t filter), (pattern, filter) ) \ + m( cairo_pattern_set_matrix, \ + (cairo_pattern_t *pattern, const cairo_matrix_t *matrix), (pattern, matrix) ) \ m( cairo_pop_group_to_source, \ (cairo_t *cr), (cr) ) \ m( cairo_push_group, \ diff --git a/src/common/graphcmn.cpp b/src/common/graphcmn.cpp index e558a254f3..99f1e81532 100644 --- a/src/common/graphcmn.cpp +++ b/src/common/graphcmn.cpp @@ -883,13 +883,15 @@ wxGraphicsBrush wxGraphicsContext::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour& c1, const wxColour& c2) const + const wxColour& c1, const wxColour& c2, + const wxGraphicsMatrix& matrix) const { return GetRenderer()->CreateLinearGradientBrush ( x1, y1, x2, y2, - wxGraphicsGradientStops(c1,c2) + wxGraphicsGradientStops(c1,c2), + matrix ); } @@ -897,36 +899,47 @@ wxGraphicsBrush wxGraphicsContext::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& gradientStops) const + const wxGraphicsGradientStops& gradientStops, + const wxGraphicsMatrix& matrix) const { - return GetRenderer()->CreateLinearGradientBrush(x1,y1,x2,y2, gradientStops); -} - -wxGraphicsBrush -wxGraphicsContext::CreateRadialGradientBrush( - wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) const -{ - return GetRenderer()->CreateRadialGradientBrush + return GetRenderer()->CreateLinearGradientBrush ( - xo, yo, - xc, yc, radius, - wxGraphicsGradientStops(oColor, cColor) + x1, y1, + x2, y2, + gradientStops, + matrix ); } wxGraphicsBrush wxGraphicsContext::CreateRadialGradientBrush( - wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, wxDouble radius, - const wxGraphicsGradientStops& gradientStops) const + wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, + const wxColour &oColor, const wxColour &cColor, + const wxGraphicsMatrix& matrix) const { return GetRenderer()->CreateRadialGradientBrush ( - xo, yo, - xc, yc, radius, - gradientStops + startX, startY, + endX, endY, radius, + wxGraphicsGradientStops(oColor, cColor), + matrix + ); +} + +wxGraphicsBrush +wxGraphicsContext::CreateRadialGradientBrush( + wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, + const wxGraphicsGradientStops& gradientStops, + const wxGraphicsMatrix& matrix) const +{ + return GetRenderer()->CreateRadialGradientBrush + ( + startX, startY, + endX, endY, radius, + gradientStops, + matrix ); } diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index f855e1e37e..c6586c98e8 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -260,6 +260,15 @@ public: virtual void Apply( wxGraphicsContext* context ); + void CreateLinearGradientPattern(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix); + void CreateRadialGradientPattern(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix); + protected: // Call this to use the given bitmap as stipple. Bitmap must be non-null // and valid. @@ -268,6 +277,8 @@ protected: // Call this to use the given hatch style. Hatch style must be valid. void InitHatch(wxHatchStyle hatchStyle); + // common part of Create{Linear,Radial}GradientPattern() + void AddGradientStops(const wxGraphicsGradientStops& stops); double m_red; double m_green; @@ -316,18 +327,8 @@ public: wxCairoBrushData( wxGraphicsRenderer* renderer ); wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush ); - void CreateLinearGradientBrush(wxDouble x1, wxDouble y1, - wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops); - void CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, wxDouble radius, - const wxGraphicsGradientStops& stops); - protected: void Init(); - - // common part of Create{Linear,Radial}GradientBrush() - void AddGradientStops(const wxGraphicsGradientStops& stops); }; class wxCairoFontData : public wxGraphicsObjectRefData @@ -721,6 +722,66 @@ void wxCairoPenBrushBaseData::Apply( wxGraphicsContext* context ) cairo_set_source_rgba(ctext, m_red, m_green, m_blue, m_alpha); } +void wxCairoPenBrushBaseData::AddGradientStops(const wxGraphicsGradientStops& stops) +{ + // loop over all the stops, they include the beginning and ending ones + const unsigned numStops = stops.GetCount(); + for ( unsigned n = 0; n < numStops; n++ ) + { + const wxGraphicsGradientStop stop = stops.Item(n); + + const wxColour col = stop.GetColour(); + + cairo_pattern_add_color_stop_rgba + ( + m_pattern, + stop.GetPosition(), + col.Red()/255.0, + col.Green()/255.0, + col.Blue()/255.0, + col.Alpha()/255.0 + ); + } + + wxASSERT_MSG(cairo_pattern_status(m_pattern) == CAIRO_STATUS_SUCCESS, + wxT("Couldn't create cairo pattern")); +} + +void +wxCairoPenBrushBaseData::CreateLinearGradientPattern(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) +{ + m_pattern = cairo_pattern_create_linear(x1,y1,x2,y2); + + if ( !matrix.IsNull() ) + { + cairo_matrix_t m = *((cairo_matrix_t*) matrix.GetNativeMatrix()); + cairo_pattern_set_matrix(m_pattern, &m); + } + + AddGradientStops(stops); +} + +void +wxCairoPenBrushBaseData::CreateRadialGradientPattern(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, + wxDouble radius, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) +{ + m_pattern = cairo_pattern_create_radial(startX,startY,0.0,endX,endY,radius); + + if ( !matrix.IsNull() ) + { + cairo_matrix_t m = *((cairo_matrix_t*) matrix.GetNativeMatrix()); + cairo_pattern_set_matrix(m_pattern, &m); + } + + AddGradientStops(stops); +} + //----------------------------------------------------------------------------- // wxCairoPenData implementation //----------------------------------------------------------------------------- @@ -732,6 +793,7 @@ wxCairoPenData::~wxCairoPenData() void wxCairoPenData::Init() { + m_pattern = NULL; m_lengths = NULL; m_userLengths = NULL; m_width = 0; @@ -867,6 +929,27 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxGraphicsPe } break; } + + switch ( info.GetGradientType() ) + { + case wxGRADIENT_NONE: + break; + + case wxGRADIENT_LINEAR: + CreateLinearGradientPattern(info.GetX1(), info.GetY1(), + info.GetX2(), info.GetY2(), + info.GetStops(), + info.GetMatrix()); + break; + + case wxGRADIENT_RADIAL: + CreateRadialGradientPattern(info.GetStartX(), info.GetStartY(), + info.GetEndX(), info.GetEndY(), + info.GetRadius(), + info.GetStops(), + info.GetMatrix()); + break; + } } void wxCairoPenData::Apply( wxGraphicsContext* context ) @@ -911,52 +994,6 @@ wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer, } } -void wxCairoBrushData::AddGradientStops(const wxGraphicsGradientStops& stops) -{ - // loop over all the stops, they include the beginning and ending ones - const unsigned numStops = stops.GetCount(); - for ( unsigned n = 0; n < numStops; n++ ) - { - const wxGraphicsGradientStop stop = stops.Item(n); - - const wxColour col = stop.GetColour(); - - cairo_pattern_add_color_stop_rgba - ( - m_pattern, - stop.GetPosition(), - col.Red()/255.0, - col.Green()/255.0, - col.Blue()/255.0, - col.Alpha()/255.0 - ); - } - - wxASSERT_MSG(cairo_pattern_status(m_pattern) == CAIRO_STATUS_SUCCESS, - wxT("Couldn't create cairo pattern")); -} - -void -wxCairoBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, - wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) -{ - m_pattern = cairo_pattern_create_linear(x1,y1,x2,y2); - - AddGradientStops(stops); -} - -void -wxCairoBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, - wxDouble radius, - const wxGraphicsGradientStops& stops) -{ - m_pattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius); - - AddGradientStops(stops); -} - void wxCairoBrushData::Init() { m_pattern = NULL; @@ -2956,13 +2993,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, + CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, - const wxGraphicsGradientStops& stops) wxOVERRIDE; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) wxOVERRIDE; // sets the font virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) wxOVERRIDE ; @@ -3150,29 +3189,32 @@ wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush ) wxGraphicsBrush wxCairoRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) { wxGraphicsBrush p; ENSURE_LOADED_OR_RETURN(p); wxCairoBrushData* d = new wxCairoBrushData( this ); - d->CreateLinearGradientBrush(x1, y1, x2, y2, stops); + d->CreateLinearGradientPattern(x1, y1, x2, y2, stops, matrix); p.SetRefData(d); return p; } wxGraphicsBrush -wxCairoRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, wxDouble r, - const wxGraphicsGradientStops& stops) +wxCairoRenderer::CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble r, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) { wxGraphicsBrush p; ENSURE_LOADED_OR_RETURN(p); wxCairoBrushData* d = new wxCairoBrushData( this ); - d->CreateRadialGradientBrush(xo, yo, xc, yc, r, stops); + d->CreateRadialGradientPattern(startX, startY, endX, endY, r, stops, matrix); p.SetRefData(d); return p; } + wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour &col ) { wxGraphicsFont p; diff --git a/src/msw/graphics.cpp b/src/msw/graphics.cpp index a23948588d..eaced69010 100644 --- a/src/msw/graphics.cpp +++ b/src/msw/graphics.cpp @@ -255,44 +255,31 @@ 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); - 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); - void CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix); + void CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, - const wxGraphicsGradientStops& stops); - - virtual Brush* GetGDIPlusBrush() { return m_brush; } - + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix); protected: - virtual void Init(); + virtual ~wxGDIPlusPenBrushBaseData(); + + Brush* m_brush; + GraphicsPath* m_brushPath; + Image* m_image; + private: // common part of Create{Linear,Radial}GradientBrush() @@ -300,10 +287,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() wxOVERRIDE; + + 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 +636,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, + CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, 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 +683,136 @@ 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 +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 colors(numStops); + wxVector 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& 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 if there is one + if ( !matrix.IsNull() ) + { + Matrix* m = static_cast(matrix.GetNativeMatrix()); + m->Invert(); + brush->MultiplyTransform(m); + } + + SetGradientStops(brush, stops); + m_brush = brush; +} + +void +wxGDIPlusPenBrushBaseData::CreateRadialGradientBrush( + wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, + wxDouble radius, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) +{ + m_brushPath = new GraphicsPath(); + m_brushPath->AddEllipse( (REAL)(endX-radius), (REAL)(endY-radius), + (REAL)(2*radius), (REAL)(2*radius)); + + PathGradientBrush * const brush = new PathGradientBrush(m_brushPath); + brush->SetCenterPoint(PointF(startX, startY)); + brush->SetCenterColor(wxColourToColor(stops.GetStartColour())); + + const Color col(wxColourToColor(stops.GetEndColour())); + int count = 1; + brush->SetSurroundColors(&col, &count); + + // TODO: There doesn't seem to be an equivallent for SetWrapMode, so + // the area outside of the gradient's radius is not getting painted. + + // Apply the matrix if there is one + if ( !matrix.IsNull() ) + { + Matrix* m = static_cast(matrix.GetNativeMatrix()); + m->Invert(); + 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 +820,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 +926,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 +967,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.GetStartX(), info.GetStartY(), + info.GetEndX(), info.GetEndY(), + info.GetRadius(), + info.GetStops()); + m_pen->SetBrush(m_brush); + break; + } } //----------------------------------------------------------------------------- @@ -846,13 +1011,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,111 +1062,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 -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 colors(numStops); - wxVector 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())); - 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 @@ -2613,26 +2690,28 @@ 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; } wxGraphicsBrush -wxGDIPlusRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, +wxGDIPlusRenderer::CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, 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(startX,startY,endX,endY,radius,stops,matrix); p.SetRefData(d); return p; } diff --git a/src/msw/graphicsd2d.cpp b/src/msw/graphicsd2d.cpp index a874e7229d..19fa4b1411 100644 --- a/src/msw/graphicsd2d.cpp +++ b/src/msw/graphicsd2d.cpp @@ -1772,9 +1772,6 @@ void wxD2DPathData::AddPath(const wxGraphicsPathData* path) GeometryStateData curStateSrc; pathSrc->SaveGeometryState(curStateSrc); - // Raise warning if appended path has an open non-empty sub-path. - wxASSERT_MSG( pathSrc->IsStateSafeForFlush(), - wxS("Sub-path in appended path should be closed prior to this operation") ); // Close appended geometry. pathSrc->Flush(); @@ -1893,8 +1890,7 @@ void wxD2DPathData::Transform(const wxGraphicsMatrixData* matrix) // constraints this can be fully done only if open figure was empty. // So, Transform() can be safely called if path doesn't contain the open // sub-path or if open sub-path is empty. - wxASSERT_MSG( IsStateSafeForFlush(), - wxS("Consider closing sub-path before calling Transform()") ); + // Close current geometry. Flush(); @@ -2425,27 +2421,46 @@ class wxD2DLinearGradientBrushResourceHolder : public wxD2DResourceHolderCreateLinearGradientBrush( D2D1::LinearGradientBrushProperties( - D2D1::Point2F(m_linearGradientInfo.direction.GetX(), m_linearGradientInfo.direction.GetY()), - D2D1::Point2F(m_linearGradientInfo.direction.GetWidth(), m_linearGradientInfo.direction.GetHeight())), + D2D1::Point2F(m_linearGradientInfo.x1, m_linearGradientInfo.y1), + D2D1::Point2F(m_linearGradientInfo.x2, m_linearGradientInfo.y2)), helper.GetGradientStopCollection(), - &m_nativeResource); + &linearGradientBrush); wxCHECK_HRESULT_RET(hr); + + if (! m_linearGradientInfo.matrix.IsNull()) + { + D2D1::Matrix3x2F matrix = wxGetD2DMatrixData(m_linearGradientInfo.matrix)->GetMatrix3x2F(); + matrix.Invert(); + linearGradientBrush->SetTransform(matrix); + } + m_nativeResource = linearGradientBrush; } private: const LinearGradientInfo m_linearGradientInfo; @@ -2455,33 +2470,54 @@ class wxD2DRadialGradientBrushResourceHolder : public wxD2DResourceHolderCreateRadialGradientBrush( D2D1::RadialGradientBrushProperties( - D2D1::Point2F(m_radialGradientInfo.direction.GetLeft(), m_radialGradientInfo.direction.GetTop()), - D2D1::Point2F(xo, yo), - m_radialGradientInfo.radius, m_radialGradientInfo.radius), + D2D1::Point2F(m_radialGradientInfo.x1, m_radialGradientInfo.y1), + D2D1::Point2F(xo, yo), + m_radialGradientInfo.radius, m_radialGradientInfo.radius), helper.GetGradientStopCollection(), - &m_nativeResource); + &radialGradientBrush); wxCHECK_HRESULT_RET(hr); + + if (! m_radialGradientInfo.matrix.IsNull()) + { + D2D1::Matrix3x2F matrix = wxGetD2DMatrixData(m_radialGradientInfo.matrix)->GetMatrix3x2F(); + matrix.Invert(); + radialGradientBrush->SetTransform(matrix); + } + m_nativeResource = radialGradientBrush; } private: @@ -2499,9 +2535,16 @@ public: wxD2DBrushData(wxGraphicsRenderer* renderer); - void CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxGraphicsGradientStops& stops); + void CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix); - void CreateRadialGradientBrush(wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, const wxGraphicsGradientStops& stops); + void CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, + wxDouble radius, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix); ID2D1Brush* GetBrush() const { @@ -2546,18 +2589,22 @@ wxD2DBrushData::wxD2DBrushData(wxGraphicsRenderer* renderer) void wxD2DBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) { - m_brushResourceHolder = new wxD2DLinearGradientBrushResourceHolder(x1, y1, x2, y2, stops); + m_brushResourceHolder = new wxD2DLinearGradientBrushResourceHolder( + x1, y1, x2, y2, stops, matrix); } void wxD2DBrushData::CreateRadialGradientBrush( - wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, + wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, - const wxGraphicsGradientStops& stops) + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) { - m_brushResourceHolder = new wxD2DRadialGradientBrushResourceHolder(xo, yo, xc, yc, radius, stops); + m_brushResourceHolder = new wxD2DRadialGradientBrushResourceHolder( + startX, startY, endX, endY, radius, stops, matrix); } wxD2DBrushData* wxGetD2DBrushData(const wxGraphicsBrush& brush) @@ -2665,9 +2712,34 @@ wxD2DPenData::wxD2DPenData( strokeBrush.SetStyle(wxBRUSHSTYLE_SOLID); } - m_stippleBrush = new wxD2DBrushData(renderer, strokeBrush); + switch ( m_penInfo.GetGradientType() ) + { + case wxGRADIENT_NONE: + m_stippleBrush = new wxD2DBrushData(renderer, strokeBrush); + break; + + case wxGRADIENT_LINEAR: + m_stippleBrush = new wxD2DBrushData(renderer); + m_stippleBrush->CreateLinearGradientBrush( + m_penInfo.GetX1(), m_penInfo.GetY1(), + m_penInfo.GetX2(), m_penInfo.GetY2(), + m_penInfo.GetStops(), + m_penInfo.GetMatrix()); + break; + + case wxGRADIENT_RADIAL: + m_stippleBrush = new wxD2DBrushData(renderer); + m_stippleBrush->CreateRadialGradientBrush( + m_penInfo.GetStartX(), m_penInfo.GetStartY(), + m_penInfo.GetEndX(), m_penInfo.GetEndY(), + m_penInfo.GetRadius(), + m_penInfo.GetStops(), + m_penInfo.GetMatrix()); + break; + } } + void wxD2DPenData::CreateStrokeStyle(ID2D1Factory* const direct2dfactory) { D2D1_CAP_STYLE capStyle = wxD2DConvertPenCap(m_penInfo.GetCap()); @@ -4558,13 +4630,15 @@ public : wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) wxOVERRIDE; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) wxOVERRIDE; wxGraphicsBrush CreateRadialGradientBrush( - wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, + wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, - const wxGraphicsGradientStops& stops) wxOVERRIDE; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) wxOVERRIDE; // create a native bitmap representation wxGraphicsBitmap CreateBitmap(const wxBitmap& bitmap) wxOVERRIDE; @@ -4749,10 +4823,11 @@ wxGraphicsBrush wxD2DRenderer::CreateBrush(const wxBrush& brush) wxGraphicsBrush wxD2DRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) { wxD2DBrushData* brushData = new wxD2DBrushData(this); - brushData->CreateLinearGradientBrush(x1, y1, x2, y2, stops); + brushData->CreateLinearGradientBrush(x1, y1, x2, y2, stops, matrix); wxGraphicsBrush brush; brush.SetRefData(brushData); @@ -4761,13 +4836,14 @@ wxGraphicsBrush wxD2DRenderer::CreateLinearGradientBrush( } wxGraphicsBrush wxD2DRenderer::CreateRadialGradientBrush( - wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, + wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, - const wxGraphicsGradientStops& stops) + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) { wxD2DBrushData* brushData = new wxD2DBrushData(this); - brushData->CreateRadialGradientBrush(xo, yo, xc, yc, radius, stops); + brushData->CreateRadialGradientBrush(startX, startY, endX, endY, radius, stops, matrix); wxGraphicsBrush brush; brush.SetRefData(brushData); diff --git a/src/osx/carbon/graphics.cpp b/src/osx/carbon/graphics.cpp index 65fe9c63a3..2ded6cf21f 100644 --- a/src/osx/carbon/graphics.cpp +++ b/src/osx/carbon/graphics.cpp @@ -87,7 +87,7 @@ extern "C" const double M_PI = 3.14159265358979; #endif -// +//----------------------------------------------------------------------------- // Pen, Brushes and Fonts // @@ -117,6 +117,7 @@ CGColorRef wxMacCreateCGColor( const wxColour& col ) return retval; } +//----------------------------------------------------------------------------- // CGPattern wrapper class: always allocate on heap, never call destructor class wxMacCoreGraphicsPattern @@ -302,17 +303,406 @@ protected : int m_hatch; }; -class wxMacCoreGraphicsPenData : public wxGraphicsObjectRefData +//----------------------------------------------------------------------------- +// Graphics Matrix data + +class WXDLLIMPEXP_CORE wxMacCoreGraphicsMatrixData : public wxGraphicsMatrixData +{ +public : + wxMacCoreGraphicsMatrixData(wxGraphicsRenderer* renderer) ; + + virtual ~wxMacCoreGraphicsMatrixData() ; + + virtual wxGraphicsObjectRefData *Clone() const wxOVERRIDE ; + + // concatenates the matrix + virtual void Concat( const wxGraphicsMatrixData *t ) wxOVERRIDE; + + // sets the matrix to the respective values + virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0, + wxDouble tx=0.0, wxDouble ty=0.0) wxOVERRIDE; + + // gets the component valuess of the matrix + virtual void Get(wxDouble* a=NULL, wxDouble* b=NULL, wxDouble* c=NULL, + wxDouble* d=NULL, wxDouble* tx=NULL, wxDouble* ty=NULL) const wxOVERRIDE; + + // makes this the inverse matrix + virtual void Invert() wxOVERRIDE; + + // returns true if the elements of the transformation matrix are equal ? + virtual bool IsEqual( const wxGraphicsMatrixData* t) const wxOVERRIDE ; + + // return true if this is the identity matrix + virtual bool IsIdentity() const wxOVERRIDE; + + // + // transformation + // + + // add the translation to this matrix + virtual void Translate( wxDouble dx , wxDouble dy ) wxOVERRIDE; + + // add the scale to this matrix + virtual void Scale( wxDouble xScale , wxDouble yScale ) wxOVERRIDE; + + // add the rotation to this matrix (radians) + virtual void Rotate( wxDouble angle ) wxOVERRIDE; + + // + // apply the transforms + // + + // applies that matrix to the point + virtual void TransformPoint( wxDouble *x, wxDouble *y ) const wxOVERRIDE; + + // applies the matrix except for translations + virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const wxOVERRIDE; + + // returns the native representation + virtual void * GetNativeMatrix() const wxOVERRIDE; + +private : + CGAffineTransform m_matrix; +} ; + + +wxMacCoreGraphicsMatrixData::wxMacCoreGraphicsMatrixData(wxGraphicsRenderer* renderer) : wxGraphicsMatrixData(renderer) +{ +} + +wxMacCoreGraphicsMatrixData::~wxMacCoreGraphicsMatrixData() +{ +} + +wxGraphicsObjectRefData *wxMacCoreGraphicsMatrixData::Clone() const +{ + wxMacCoreGraphicsMatrixData* m = new wxMacCoreGraphicsMatrixData(GetRenderer()) ; + m->m_matrix = m_matrix ; + return m; +} + +// concatenates the matrix +void wxMacCoreGraphicsMatrixData::Concat( const wxGraphicsMatrixData *t ) +{ + m_matrix = CGAffineTransformConcat(*((CGAffineTransform*) t->GetNativeMatrix()), m_matrix ); +} + +// sets the matrix to the respective values +void wxMacCoreGraphicsMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, + wxDouble tx, wxDouble ty) +{ + m_matrix = CGAffineTransformMake((CGFloat) a,(CGFloat) b,(CGFloat) c,(CGFloat) d,(CGFloat) tx,(CGFloat) ty); +} + +// gets the component valuess of the matrix +void wxMacCoreGraphicsMatrixData::Get(wxDouble* a, wxDouble* b, wxDouble* c, + wxDouble* d, wxDouble* tx, wxDouble* ty) const +{ + if (a) *a = m_matrix.a; + if (b) *b = m_matrix.b; + if (c) *c = m_matrix.c; + if (d) *d = m_matrix.d; + if (tx) *tx= m_matrix.tx; + if (ty) *ty= m_matrix.ty; +} + +// makes this the inverse matrix +void wxMacCoreGraphicsMatrixData::Invert() +{ + m_matrix = CGAffineTransformInvert( m_matrix ); +} + +// returns true if the elements of the transformation matrix are equal ? +bool wxMacCoreGraphicsMatrixData::IsEqual( const wxGraphicsMatrixData* t) const +{ + return CGAffineTransformEqualToTransform(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix())); +} + +// return true if this is the identity matrix +bool wxMacCoreGraphicsMatrixData::IsIdentity() const +{ + return ( m_matrix.a == 1 && m_matrix.d == 1 && + m_matrix.b == 0 && m_matrix.d == 0 && m_matrix.tx == 0 && m_matrix.ty == 0); +} + +// +// transformation +// + +// add the translation to this matrix +void wxMacCoreGraphicsMatrixData::Translate( wxDouble dx , wxDouble dy ) +{ + m_matrix = CGAffineTransformTranslate( m_matrix, (CGFloat) dx, (CGFloat) dy); +} + +// add the scale to this matrix +void wxMacCoreGraphicsMatrixData::Scale( wxDouble xScale , wxDouble yScale ) +{ + m_matrix = CGAffineTransformScale( m_matrix, (CGFloat) xScale, (CGFloat) yScale); +} + +// add the rotation to this matrix (radians) +void wxMacCoreGraphicsMatrixData::Rotate( wxDouble angle ) +{ + m_matrix = CGAffineTransformRotate( m_matrix, (CGFloat) angle); +} + +// +// apply the transforms +// + +// applies that matrix to the point +void wxMacCoreGraphicsMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const +{ + CGPoint pt = CGPointApplyAffineTransform( CGPointMake((CGFloat) *x,(CGFloat) *y), m_matrix); + + *x = pt.x; + *y = pt.y; +} + +// applies the matrix except for translations +void wxMacCoreGraphicsMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const +{ + CGSize sz = CGSizeApplyAffineTransform( CGSizeMake((CGFloat) *dx,(CGFloat) *dy) , m_matrix ); + *dx = sz.width; + *dy = sz.height; +} + +// returns the native representation +void * wxMacCoreGraphicsMatrixData::GetNativeMatrix() const +{ + return (void*) &m_matrix; +} + + + +// ---------------------------------------------------------------------------- +// Pen and Brush common data. Base class for information shared between pens and +// brushes, basically just the things needed for gradient support. + +class wxMacCoreGraphicsPenBrushDataBase : public wxGraphicsObjectRefData +{ +public: + wxMacCoreGraphicsPenBrushDataBase(wxGraphicsRenderer* renderer); + ~wxMacCoreGraphicsPenBrushDataBase(); + + void CreateLinearGradientShading(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix); + void CreateRadialGradientShading(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix); + + virtual bool IsShading() { return m_isShading; } + CGShadingRef GetShading() { return m_shading; } + wxMacCoreGraphicsMatrixData* GetMatrix() { return m_shadingMatrix; } + +protected: + void Init(); + + CGFunctionRef CreateGradientFunction(const wxGraphicsGradientStops& stops); + static void CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out); + + bool m_isShading; + CGFunctionRef m_gradientFunction; + CGShadingRef m_shading; + wxMacCoreGraphicsMatrixData* m_shadingMatrix; + + // information about a single gradient component + struct GradientComponent + { + CGFloat pos; + CGFloat red; + CGFloat green; + CGFloat blue; + CGFloat alpha; + }; + + // and information about all of them + struct GradientComponents + { + GradientComponents() + { + count = 0; + comps = NULL; + } + + void Init(unsigned count_) + { + count = count_; + comps = new GradientComponent[count]; + } + + ~GradientComponents() + { + delete [] comps; + } + + unsigned count; + GradientComponent *comps; + }; + + GradientComponents m_gradientComponents; +}; + + +wxMacCoreGraphicsPenBrushDataBase::wxMacCoreGraphicsPenBrushDataBase(wxGraphicsRenderer* renderer) + : wxGraphicsObjectRefData(renderer) +{ + Init(); +} + +wxMacCoreGraphicsPenBrushDataBase::~wxMacCoreGraphicsPenBrushDataBase() +{ + if ( m_shading ) + CGShadingRelease(m_shading); + + if ( m_gradientFunction ) + CGFunctionRelease(m_gradientFunction); + + if ( m_shadingMatrix ) + delete m_shadingMatrix; +} + +void +wxMacCoreGraphicsPenBrushDataBase::Init() +{ + m_gradientFunction = NULL; + m_shading = NULL; + m_isShading = false; + m_shadingMatrix = NULL; +} + +void +wxMacCoreGraphicsPenBrushDataBase::CreateLinearGradientShading( + wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) +{ + m_gradientFunction = CreateGradientFunction(stops); + m_shading = CGShadingCreateAxial( wxMacGetGenericRGBColorSpace(), + CGPointMake((CGFloat) x1, (CGFloat) y1), + CGPointMake((CGFloat) x2, (CGFloat) y2), + m_gradientFunction, true, true ); + m_isShading = true; + if ( !matrix.IsNull() ) + { + m_shadingMatrix = (wxMacCoreGraphicsMatrixData*)((wxMacCoreGraphicsMatrixData*)matrix.GetRefData())->Clone(); + m_shadingMatrix->Invert(); + } +} + +void +wxMacCoreGraphicsPenBrushDataBase::CreateRadialGradientShading( + wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, + wxDouble radius, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) +{ + m_gradientFunction = CreateGradientFunction(stops); + m_shading = CGShadingCreateRadial( wxMacGetGenericRGBColorSpace(), + CGPointMake((CGFloat) startX, (CGFloat) startY), 0, + CGPointMake((CGFloat) endX, (CGFloat) endY), (CGFloat) radius, + m_gradientFunction, true, true ); + m_isShading = true; + if ( !matrix.IsNull() ) + { + m_shadingMatrix = (wxMacCoreGraphicsMatrixData*)((wxMacCoreGraphicsMatrixData*)matrix.GetRefData())->Clone(); + m_shadingMatrix->Invert(); + } +} + +void wxMacCoreGraphicsPenBrushDataBase::CalculateShadingValues(void *info, const CGFloat *in, CGFloat *out) +{ + const GradientComponents& stops = *(GradientComponents*) info ; + + CGFloat f = *in; + if (f <= 0.0) + { + // Start + out[0] = stops.comps[0].red; + out[1] = stops.comps[0].green; + out[2] = stops.comps[0].blue; + out[3] = stops.comps[0].alpha; + } + else if (f >= 1.0) + { + // end + out[0] = stops.comps[stops.count - 1].red; + out[1] = stops.comps[stops.count - 1].green; + out[2] = stops.comps[stops.count - 1].blue; + out[3] = stops.comps[stops.count - 1].alpha; + } + else + { + // Find first component with position greater than f + unsigned i; + for ( i = 0; i < stops.count; i++ ) + { + if (stops.comps[i].pos > f) + break; + } + + // Interpolated between stops + CGFloat diff = (f - stops.comps[i-1].pos); + CGFloat range = (stops.comps[i].pos - stops.comps[i-1].pos); + CGFloat fact = diff / range; + + out[0] = stops.comps[i - 1].red + (stops.comps[i].red - stops.comps[i - 1].red) * fact; + out[1] = stops.comps[i - 1].green + (stops.comps[i].green - stops.comps[i - 1].green) * fact; + out[2] = stops.comps[i - 1].blue + (stops.comps[i].blue - stops.comps[i - 1].blue) * fact; + out[3] = stops.comps[i - 1].alpha + (stops.comps[i].alpha - stops.comps[i - 1].alpha) * fact; + } +} + +CGFunctionRef +wxMacCoreGraphicsPenBrushDataBase::CreateGradientFunction(const wxGraphicsGradientStops& stops) +{ + + static const CGFunctionCallbacks callbacks = { 0, &CalculateShadingValues, NULL }; + static const CGFloat input_value_range [2] = { 0, 1 }; + static const CGFloat output_value_ranges [8] = { 0, 1, 0, 1, 0, 1, 0, 1 }; + + m_gradientComponents.Init(stops.GetCount()); + for ( unsigned i = 0; i < m_gradientComponents.count; i++ ) + { + const wxGraphicsGradientStop stop = stops.Item(i); + + m_gradientComponents.comps[i].pos = stop.GetPosition(); + + const wxColour col = stop.GetColour(); + m_gradientComponents.comps[i].red = (CGFloat) (col.Red() / 255.0); + m_gradientComponents.comps[i].green = (CGFloat) (col.Green() / 255.0); + m_gradientComponents.comps[i].blue = (CGFloat) (col.Blue() / 255.0); + m_gradientComponents.comps[i].alpha = (CGFloat) (col.Alpha() / 255.0); + } + + return CGFunctionCreate ( &m_gradientComponents, 1, + input_value_range, + 4, + output_value_ranges, + &callbacks); +} + +//----------------------------------------------------------------------------- +// Pen data + +class wxMacCoreGraphicsPenData : public wxMacCoreGraphicsPenBrushDataBase { public: wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer, const wxGraphicsPenInfo& info ); ~wxMacCoreGraphicsPenData(); - void Init(); virtual void Apply( wxGraphicsContext* context ); virtual wxDouble GetWidth() { return m_width; } protected : + void Init(); + CGLineCap m_cap; wxCFRef m_color; wxCFRef m_colorSpace; @@ -332,7 +722,7 @@ protected : wxMacCoreGraphicsPenData::wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer, const wxGraphicsPenInfo& info ) - : wxGraphicsObjectRefData( renderer ) + : wxMacCoreGraphicsPenBrushDataBase( renderer ) { Init(); @@ -457,7 +847,7 @@ wxMacCoreGraphicsPenData::wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer m_patternColorComponents[0] = (CGFloat) (info.GetColour().Red() / 255.0); m_patternColorComponents[1] = (CGFloat) (info.GetColour().Green() / 255.0); m_patternColorComponents[2] = (CGFloat) (info.GetColour().Blue() / 255.0); - m_patternColorComponents[3] = (CGFloat) (info.GetColour().Alpha() / 255.0); + m_patternColorComponents[3] = (CGFloat) (info.GetColour().Alpha() / 255.0); } break; } @@ -466,6 +856,28 @@ wxMacCoreGraphicsPenData::wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer // force the line cap, otherwise we get artifacts (overlaps) and just solid lines m_cap = kCGLineCapButt; } + + switch ( info.GetGradientType() ) + { + case wxGRADIENT_NONE: + break; + + case wxGRADIENT_LINEAR: + CreateLinearGradientShading(info.GetX1(), info.GetY1(), + info.GetX2(), info.GetY2(), + info.GetStops(), + info.GetMatrix()); + break; + + case wxGRADIENT_RADIAL: + CreateRadialGradientShading(info.GetStartX(), info.GetStartY(), + info.GetEndX(), info.GetEndY(), + info.GetRadius(), + info.GetStops(), + info.GetMatrix()); + break; + } + } wxMacCoreGraphicsPenData::~wxMacCoreGraphicsPenData() @@ -506,9 +918,8 @@ void wxMacCoreGraphicsPenData::Apply( wxGraphicsContext* context ) } } -// -// Brush -// +//----------------------------------------------------------------------------- +// Brush data and supporting colour class // make sure we all use one class for all conversions from wx to native colour @@ -595,7 +1006,7 @@ wxMacCoreGraphicsColour::wxMacCoreGraphicsColour( const wxBrush &brush ) } } -class wxMacCoreGraphicsBrushData : public wxGraphicsObjectRefData +class wxMacCoreGraphicsBrushData : public wxMacCoreGraphicsPenBrushDataBase { public: wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer ); @@ -603,113 +1014,24 @@ public: ~wxMacCoreGraphicsBrushData (); virtual void Apply( wxGraphicsContext* context ); - void CreateLinearGradientBrush(wxDouble x1, wxDouble y1, - wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops); - void CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, wxDouble radius, - const wxGraphicsGradientStops& stops); - virtual bool IsShading() { return m_isShading; } - CGShadingRef GetShading() { return m_shading; } protected: - CGFunctionRef CreateGradientFunction(const wxGraphicsGradientStops& stops); - - static void CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out); - virtual void Init(); - wxMacCoreGraphicsColour m_cgColor; - - bool m_isShading; - CGFunctionRef m_gradientFunction; - CGShadingRef m_shading; - - // information about a single gradient component - struct GradientComponent - { - CGFloat pos; - CGFloat red; - CGFloat green; - CGFloat blue; - CGFloat alpha; - }; - - // and information about all of them - struct GradientComponents - { - GradientComponents() - { - count = 0; - comps = NULL; - } - - void Init(unsigned count_) - { - count = count_; - comps = new GradientComponent[count]; - } - - ~GradientComponents() - { - delete [] comps; - } - - unsigned count; - GradientComponent *comps; - }; - - GradientComponents m_gradientComponents; }; -wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer) : wxGraphicsObjectRefData( renderer ) +wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer) : + wxMacCoreGraphicsPenBrushDataBase( renderer ) { - Init(); } -void -wxMacCoreGraphicsBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, - wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) -{ - m_gradientFunction = CreateGradientFunction(stops); - m_shading = CGShadingCreateAxial( wxMacGetGenericRGBColorSpace(), CGPointMake((CGFloat) x1, (CGFloat) y1), - CGPointMake((CGFloat) x2,(CGFloat) y2), m_gradientFunction, true, true ) ; - m_isShading = true ; -} - -void -wxMacCoreGraphicsBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, - wxDouble radius, - const wxGraphicsGradientStops& stops) -{ - m_gradientFunction = CreateGradientFunction(stops); - m_shading = CGShadingCreateRadial( wxMacGetGenericRGBColorSpace(), CGPointMake((CGFloat) xo,(CGFloat) yo), 0, - CGPointMake((CGFloat) xc,(CGFloat) yc), (CGFloat) radius, m_gradientFunction, true, true ) ; - m_isShading = true ; -} - -wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData(wxGraphicsRenderer* renderer, const wxBrush &brush) : wxGraphicsObjectRefData( renderer ), +wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData(wxGraphicsRenderer* renderer, const wxBrush &brush) : + wxMacCoreGraphicsPenBrushDataBase( renderer ), m_cgColor( brush ) { - Init(); - } wxMacCoreGraphicsBrushData::~wxMacCoreGraphicsBrushData() { - if ( m_shading ) - CGShadingRelease(m_shading); - - if( m_gradientFunction ) - CGFunctionRelease(m_gradientFunction); -} - -void wxMacCoreGraphicsBrushData::Init() -{ - m_gradientFunction = NULL; - m_shading = NULL; - m_isShading = false; } void wxMacCoreGraphicsBrushData::Apply( wxGraphicsContext* context ) @@ -726,81 +1048,9 @@ void wxMacCoreGraphicsBrushData::Apply( wxGraphicsContext* context ) } } -void wxMacCoreGraphicsBrushData::CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out) -{ - const GradientComponents& stops = *(GradientComponents*) info ; - CGFloat f = *in; - if (f <= 0.0) - { - // Start - out[0] = stops.comps[0].red; - out[1] = stops.comps[0].green; - out[2] = stops.comps[0].blue; - out[3] = stops.comps[0].alpha; - } - else if (f >= 1.0) - { - // end - out[0] = stops.comps[stops.count - 1].red; - out[1] = stops.comps[stops.count - 1].green; - out[2] = stops.comps[stops.count - 1].blue; - out[3] = stops.comps[stops.count - 1].alpha; - } - else - { - // Find first component with position greater than f - unsigned i; - for ( i = 0; i < stops.count; i++ ) - { - if (stops.comps[i].pos > f) - break; - } - - // Interpolated between stops - CGFloat diff = (f - stops.comps[i-1].pos); - CGFloat range = (stops.comps[i].pos - stops.comps[i-1].pos); - CGFloat fact = diff / range; - - out[0] = stops.comps[i - 1].red + (stops.comps[i].red - stops.comps[i - 1].red) * fact; - out[1] = stops.comps[i - 1].green + (stops.comps[i].green - stops.comps[i - 1].green) * fact; - out[2] = stops.comps[i - 1].blue + (stops.comps[i].blue - stops.comps[i - 1].blue) * fact; - out[3] = stops.comps[i - 1].alpha + (stops.comps[i].alpha - stops.comps[i - 1].alpha) * fact; - } -} - -CGFunctionRef -wxMacCoreGraphicsBrushData::CreateGradientFunction(const wxGraphicsGradientStops& stops) -{ - - static const CGFunctionCallbacks callbacks = { 0, &CalculateShadingValues, NULL }; - static const CGFloat input_value_range [2] = { 0, 1 }; - static const CGFloat output_value_ranges [8] = { 0, 1, 0, 1, 0, 1, 0, 1 }; - - m_gradientComponents.Init(stops.GetCount()); - for ( unsigned i = 0; i < m_gradientComponents.count; i++ ) - { - const wxGraphicsGradientStop stop = stops.Item(i); - - m_gradientComponents.comps[i].pos = stop.GetPosition(); - - const wxColour col = stop.GetColour(); - m_gradientComponents.comps[i].red = (CGFloat) (col.Red() / 255.0); - m_gradientComponents.comps[i].green = (CGFloat) (col.Green() / 255.0); - m_gradientComponents.comps[i].blue = (CGFloat) (col.Blue() / 255.0); - m_gradientComponents.comps[i].alpha = (CGFloat) (col.Alpha() / 255.0); - } - - return CGFunctionCreate ( &m_gradientComponents, 1, - input_value_range, - 4, - output_value_ranges, - &callbacks); -} - -// -// Font -// +//----------------------------------------------------------------------------- +// Font data class wxMacCoreGraphicsFontData : public wxGraphicsObjectRefData { @@ -829,8 +1079,9 @@ private : #endif }; -wxMacCoreGraphicsFontData::wxMacCoreGraphicsFontData(wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col) : wxGraphicsObjectRefData( renderer ) - , m_colour(col) +wxMacCoreGraphicsFontData::wxMacCoreGraphicsFontData(wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col) + : wxGraphicsObjectRefData( renderer ), + m_colour(col) { m_underlined = font.GetUnderlined(); m_strikethrough = font.GetStrikethrough(); @@ -846,6 +1097,9 @@ wxMacCoreGraphicsFontData::~wxMacCoreGraphicsFontData() { } +//----------------------------------------------------------------------------- +// Bitmap data + class wxMacCoreGraphicsBitmapData : public wxGraphicsBitmapData { public: @@ -879,192 +1133,8 @@ wxMacCoreGraphicsBitmapData::~wxMacCoreGraphicsBitmapData() } -// -// Graphics Matrix -// - -//----------------------------------------------------------------------------- -// wxMacCoreGraphicsMatrix declaration -//----------------------------------------------------------------------------- - -class WXDLLIMPEXP_CORE wxMacCoreGraphicsMatrixData : public wxGraphicsMatrixData -{ -public : - wxMacCoreGraphicsMatrixData(wxGraphicsRenderer* renderer) ; - - virtual ~wxMacCoreGraphicsMatrixData() ; - - virtual wxGraphicsObjectRefData *Clone() const wxOVERRIDE ; - - // concatenates the matrix - virtual void Concat( const wxGraphicsMatrixData *t ) wxOVERRIDE; - - // sets the matrix to the respective values - virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0, - wxDouble tx=0.0, wxDouble ty=0.0) wxOVERRIDE; - - // gets the component valuess of the matrix - virtual void Get(wxDouble* a=NULL, wxDouble* b=NULL, wxDouble* c=NULL, - wxDouble* d=NULL, wxDouble* tx=NULL, wxDouble* ty=NULL) const wxOVERRIDE; - - // makes this the inverse matrix - virtual void Invert() wxOVERRIDE; - - // returns true if the elements of the transformation matrix are equal ? - virtual bool IsEqual( const wxGraphicsMatrixData* t) const wxOVERRIDE ; - - // return true if this is the identity matrix - virtual bool IsIdentity() const wxOVERRIDE; - - // - // transformation - // - - // add the translation to this matrix - virtual void Translate( wxDouble dx , wxDouble dy ) wxOVERRIDE; - - // add the scale to this matrix - virtual void Scale( wxDouble xScale , wxDouble yScale ) wxOVERRIDE; - - // add the rotation to this matrix (radians) - virtual void Rotate( wxDouble angle ) wxOVERRIDE; - - // - // apply the transforms - // - - // applies that matrix to the point - virtual void TransformPoint( wxDouble *x, wxDouble *y ) const wxOVERRIDE; - - // applies the matrix except for translations - virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const wxOVERRIDE; - - // returns the native representation - virtual void * GetNativeMatrix() const wxOVERRIDE; - -private : - CGAffineTransform m_matrix; -} ; - -//----------------------------------------------------------------------------- -// wxMacCoreGraphicsMatrix implementation -//----------------------------------------------------------------------------- - -wxMacCoreGraphicsMatrixData::wxMacCoreGraphicsMatrixData(wxGraphicsRenderer* renderer) : wxGraphicsMatrixData(renderer) -{ -} - -wxMacCoreGraphicsMatrixData::~wxMacCoreGraphicsMatrixData() -{ -} - -wxGraphicsObjectRefData *wxMacCoreGraphicsMatrixData::Clone() const -{ - wxMacCoreGraphicsMatrixData* m = new wxMacCoreGraphicsMatrixData(GetRenderer()) ; - m->m_matrix = m_matrix ; - return m; -} - -// concatenates the matrix -void wxMacCoreGraphicsMatrixData::Concat( const wxGraphicsMatrixData *t ) -{ - m_matrix = CGAffineTransformConcat(*((CGAffineTransform*) t->GetNativeMatrix()), m_matrix ); -} - -// sets the matrix to the respective values -void wxMacCoreGraphicsMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, - wxDouble tx, wxDouble ty) -{ - m_matrix = CGAffineTransformMake((CGFloat) a,(CGFloat) b,(CGFloat) c,(CGFloat) d,(CGFloat) tx,(CGFloat) ty); -} - -// gets the component valuess of the matrix -void wxMacCoreGraphicsMatrixData::Get(wxDouble* a, wxDouble* b, wxDouble* c, - wxDouble* d, wxDouble* tx, wxDouble* ty) const -{ - if (a) *a = m_matrix.a; - if (b) *b = m_matrix.b; - if (c) *c = m_matrix.c; - if (d) *d = m_matrix.d; - if (tx) *tx= m_matrix.tx; - if (ty) *ty= m_matrix.ty; -} - -// makes this the inverse matrix -void wxMacCoreGraphicsMatrixData::Invert() -{ - m_matrix = CGAffineTransformInvert( m_matrix ); -} - -// returns true if the elements of the transformation matrix are equal ? -bool wxMacCoreGraphicsMatrixData::IsEqual( const wxGraphicsMatrixData* t) const -{ - return CGAffineTransformEqualToTransform(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix())); -} - -// return true if this is the identity matrix -bool wxMacCoreGraphicsMatrixData::IsIdentity() const -{ - return ( m_matrix.a == 1 && m_matrix.d == 1 && - m_matrix.b == 0 && m_matrix.d == 0 && m_matrix.tx == 0 && m_matrix.ty == 0); -} - -// -// transformation -// - -// add the translation to this matrix -void wxMacCoreGraphicsMatrixData::Translate( wxDouble dx , wxDouble dy ) -{ - m_matrix = CGAffineTransformTranslate( m_matrix, (CGFloat) dx, (CGFloat) dy); -} - -// add the scale to this matrix -void wxMacCoreGraphicsMatrixData::Scale( wxDouble xScale , wxDouble yScale ) -{ - m_matrix = CGAffineTransformScale( m_matrix, (CGFloat) xScale, (CGFloat) yScale); -} - -// add the rotation to this matrix (radians) -void wxMacCoreGraphicsMatrixData::Rotate( wxDouble angle ) -{ - m_matrix = CGAffineTransformRotate( m_matrix, (CGFloat) angle); -} - -// -// apply the transforms -// - -// applies that matrix to the point -void wxMacCoreGraphicsMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const -{ - CGPoint pt = CGPointApplyAffineTransform( CGPointMake((CGFloat) *x,(CGFloat) *y), m_matrix); - - *x = pt.x; - *y = pt.y; -} - -// applies the matrix except for translations -void wxMacCoreGraphicsMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const -{ - CGSize sz = CGSizeApplyAffineTransform( CGSizeMake((CGFloat) *dx,(CGFloat) *dy) , m_matrix ); - *dx = sz.width; - *dy = sz.height; -} - -// returns the native representation -void * wxMacCoreGraphicsMatrixData::GetNativeMatrix() const -{ - return (void*) &m_matrix; -} - -// -// Graphics Path -// - -//----------------------------------------------------------------------------- -// wxMacCoreGraphicsPath declaration //----------------------------------------------------------------------------- +// Graphics Path data class WXDLLEXPORT wxMacCoreGraphicsPathData : public wxGraphicsPathData { @@ -1133,9 +1203,6 @@ private : CGMutablePathRef m_path; }; -//----------------------------------------------------------------------------- -// wxMacCoreGraphicsPath implementation -//----------------------------------------------------------------------------- wxMacCoreGraphicsPathData::wxMacCoreGraphicsPathData( wxGraphicsRenderer* renderer, CGMutablePathRef path) : wxGraphicsPathData(renderer) { @@ -1292,13 +1359,9 @@ bool wxMacCoreGraphicsPathData::Contains( wxDouble x, wxDouble y, wxPolygonFillM return CGPathContainsPoint( m_path, NULL, CGPointMake((CGFloat) x,(CGFloat) y), fillStyle == wxODDEVEN_RULE ); } -// -// Graphics Context -// //----------------------------------------------------------------------------- -// wxMacCoreGraphicsContext declaration -//----------------------------------------------------------------------------- +// Graphics Context class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext { @@ -1464,7 +1527,7 @@ private: // device context implementation // // more and more of the dc functionality should be implemented by calling -// the appropricate wxMacCoreGraphicsContext, but we will have to do that step by step +// the appropriate wxMacCoreGraphicsContext, but we will have to do that step by step // also coordinate conversions should be moved to native matrix ops //----------------------------------------------------------------------------- @@ -2052,10 +2115,33 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path ) return; wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() ); + wxMacCoreGraphicsPenData* penData = (wxMacCoreGraphicsPenData*)m_pen.GetRefData(); - ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this); - CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() ); - CGContextStrokePath( m_cgContext ); + penData->Apply(this); + + if (penData->IsShading()) + { + // To stroke with a gradient we first have to turn the path into a path + // that is essentially the outline of the original stroke, and then fill + // that path. + CGContextSaveGState( m_cgContext ); + CGContextAddPath( m_cgContext, (CGPathRef)path.GetNativePath() ); + CGContextReplacePathWithStrokedPath(m_cgContext); + CGContextClip( m_cgContext ); + // Apply the gradient's transform, if there is one. + if ( penData->GetMatrix() != NULL ) + { + wxMacCoreGraphicsMatrixData* m = penData->GetMatrix(); + CGContextConcatCTM( m_cgContext, *(CGAffineTransform*) m->GetNativeMatrix()); + } + CGContextDrawShading( m_cgContext, penData->GetShading() ); + CGContextRestoreGState( m_cgContext); + } + else + { + CGContextAddPath( m_cgContext, (CGPathRef)path.GetNativePath() ); + CGContextStrokePath( m_cgContext ); + } CheckInvariants(); } @@ -2068,7 +2154,8 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonF if (m_composition == wxCOMPOSITION_DEST) return; - if ( !m_brush.IsNull() && ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() ) + if ( (!m_brush.IsNull() && ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading()) || + (!m_pen.IsNull() && ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->IsShading()) ) { // when using shading, we cannot draw pen and brush at the same time // revert to the base implementation of first filling and then stroking @@ -2126,12 +2213,20 @@ void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , wxPolygonF if (m_composition == wxCOMPOSITION_DEST) return; - if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() ) + wxMacCoreGraphicsBrushData* brushData = (wxMacCoreGraphicsBrushData*)m_brush.GetRefData(); + + if ( brushData->IsShading() ) { CGContextSaveGState( m_cgContext ); CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() ); CGContextClip( m_cgContext ); - CGContextDrawShading( m_cgContext, ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->GetShading() ); + // Apply the gradient's transform, if there is one. + if ( brushData->GetMatrix() != NULL ) + { + wxMacCoreGraphicsMatrixData* m = brushData->GetMatrix(); + CGContextConcatCTM( m_cgContext, *(CGAffineTransform*) m->GetNativeMatrix()); + } + CGContextDrawShading( m_cgContext, brushData->GetShading() ); CGContextRestoreGState( m_cgContext); } else @@ -2667,13 +2762,15 @@ public : virtual wxGraphicsBrush CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) wxOVERRIDE; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) wxOVERRIDE; virtual wxGraphicsBrush - CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, + CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, - const wxGraphicsGradientStops& stops) wxOVERRIDE; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) wxOVERRIDE; // sets the font virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) wxOVERRIDE ; @@ -2924,24 +3021,26 @@ void wxMacCoreGraphicsRenderer::GetVersion(int *major, int *minor, int *micro) c wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) { wxGraphicsBrush p; wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this ); - d->CreateLinearGradientBrush(x1, y1, x2, y2, stops); + d->CreateLinearGradientShading(x1, y1, x2, y2, stops, matrix); p.SetRefData(d); return p; } wxGraphicsBrush -wxMacCoreGraphicsRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, +wxMacCoreGraphicsRenderer::CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, - const wxGraphicsGradientStops& stops) + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix) { wxGraphicsBrush p; wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this ); - d->CreateRadialGradientBrush(xo, yo, xc, yc, radius, stops); + d->CreateRadialGradientShading(startX, startY, endX, endY, radius, stops, matrix); p.SetRefData(d); return p; } diff --git a/src/qt/graphics.cpp b/src/qt/graphics.cpp index be97b85cfe..c427099b08 100644 --- a/src/qt/graphics.cpp +++ b/src/qt/graphics.cpp @@ -91,12 +91,12 @@ public: m_brush = QBrush(gradient); } - void CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, + void CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, const wxGraphicsGradientStops& stops) { - QRadialGradient gradient(QPointF(xc, yc), radius, QPointF(xo, yo)); + QRadialGradient gradient(QPointF(endX, endY), radius, QPointF(startX, startY)); SetStops(gradient, stops); m_brush = QBrush(gradient); } @@ -1137,13 +1137,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, + CreateRadialGradientBrush(wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble radius, - const wxGraphicsGradientStops& stops) wxOVERRIDE; + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) wxOVERRIDE; // sets the font virtual wxGraphicsFont CreateFont(const wxFont& font, @@ -1274,7 +1276,8 @@ wxGraphicsBrush wxQtGraphicsRenderer::CreateBrush(const wxBrush& brush) wxGraphicsBrush wxQtGraphicsRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxGraphicsGradientStops& stops) + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& WXUNUSED(matrix)) { wxGraphicsBrush p; wxQtBrushData* d = new wxQtBrushData(this); @@ -1284,13 +1287,14 @@ wxGraphicsBrush wxQtGraphicsRenderer::CreateLinearGradientBrush( } wxGraphicsBrush wxQtGraphicsRenderer::CreateRadialGradientBrush( - wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, wxDouble r, - const wxGraphicsGradientStops& stops) + wxDouble startX, wxDouble startY, + wxDouble endX, wxDouble endY, wxDouble r, + const wxGraphicsGradientStops& stops, + const wxGraphicsMatrix& WXUNUSED(matrix)) { wxGraphicsBrush p; wxQtBrushData* d = new wxQtBrushData(this); - d->CreateRadialGradientBrush(xo, yo, xc, yc, r, stops); + d->CreateRadialGradientBrush(startX, startY, endX, endY, r, stops); p.SetRefData(d); return p; }