From: Vadim Zeitlin Date: Mon, 5 Apr 2010 12:15:11 +0000 (+0000) Subject: Add support for gradient stops to wxGraphicsContext. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/4ee4c7b948e76377a6947d3ffbe5099870d0c3e9 Add support for gradient stops to wxGraphicsContext. Allow specifying a set of gradient stops instead of just the beginning and ending colours. Add the new wxGraphicsGradientStop(s) classes and new wxGraphicsContext::Create{Linear,Radial}GradientBrush() overloads. Also change the same methods of wxGraphicsRenderer to take wxGraphicsGradientStops instead of a pair of colours. Implement the new API for MSW and Cairo. OS X still uses just the two colours for now. Closes #11897. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@63857 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/changes.txt b/docs/changes.txt index 59306d7a6b..8ad5b40a3b 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -499,6 +499,7 @@ All (GUI): - Add "initial selection" parameter to wxGetSingleChoice() (Nikolay Tjushkov). - Implement wxDocument::Revert() (troelsk). - Allow overriding print preview frame creation in docview (troelsk). +- Added support for gradient stops in wxGraphicsContext (Kit Bishop). - Added wxTransparentColour. GTK: diff --git a/include/wx/graphics.h b/include/wx/graphics.h index 34f92d7cd5..392c13044c 100644 --- a/include/wx/graphics.h +++ b/include/wx/graphics.h @@ -19,6 +19,7 @@ #include "wx/geometry.h" #include "wx/dynarray.h" #include "wx/dc.h" +#include "wx/vector.h" enum wxAntialiasMode { @@ -304,6 +305,81 @@ private: extern WXDLLIMPEXP_DATA_CORE(wxGraphicsPath) wxNullGraphicsPath; +// Describes a single gradient stop. +class wxGraphicsGradientStop +{ +public: + wxGraphicsGradientStop(wxColour col, float pos) + : 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.)); + m_stops.push_back(wxGraphicsGradientStop(endCol, 1.)); + } + + // 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. + unsigned 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: @@ -348,14 +424,29 @@ public: virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) const; - // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 - virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) const; - - // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) - // with radius r and color cColor - virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) const; + // sets the brush to a linear gradient, starting at (x1,y1) and ending at + // (x2,y2) with the given boundary colours or the specified stops + wxGraphicsBrush + CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxColour& c1, const wxColour& c2) const; + wxGraphicsBrush + CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) 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; + + wxGraphicsBrush + CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, wxDouble radius, + const wxGraphicsGradientStops& stops) const; // sets the font virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) const; @@ -644,21 +735,26 @@ public: virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) = 0; - // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 - virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) = 0; + // Gradient brush creation functions may not honour all the stops specified + // stops and use just its boundary colours (this is currently the case + // under OS X) + virtual wxGraphicsBrush + CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) = 0; - // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) - // with radius r and color cColor - virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) = 0; + virtual wxGraphicsBrush + CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops) = 0; - // sets the font + // sets the font virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) = 0; // create a native bitmap representation virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) = 0; - + // create a graphics bitmap from a native bitmap virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap( void* bitmap ) = 0; diff --git a/interface/wx/graphics.h b/interface/wx/graphics.h index 10c2ea7485..638787d069 100644 --- a/interface/wx/graphics.h +++ b/interface/wx/graphics.h @@ -206,14 +206,14 @@ public: enum wxAntialiasMode { /** No anti-aliasing */ - wxANTIALIAS_NONE, - + wxANTIALIAS_NONE, + /** The default anti-aliasing */ wxANTIALIAS_DEFAULT, }; /** - Compositing is done using Porter-Duff compositions + Compositing is done using Porter-Duff compositions (see http://keithp.com/~keithp/porterduff/p253-porter.pdf) with wxGraphicsContext::SetCompositionMode @@ -361,15 +361,25 @@ public: static wxGraphicsContext* CreateFromNativeWindow(void* window); /** - Creates a native brush, having a linear gradient, starting at - (@a x1, @a y1) with color @a c1 to (@a x2, @a y2) with color @a c2. + Creates a native brush with a linear gradient. + + The brush starts at (@a x1, @a y1) and ends at (@a x2, @a y2). Either + just the start and end gradient colours (@a c1 and @a c2) or full set + of gradient @a stops can be specified. + + The version taking wxGraphicsGradientStops is new in wxWidgets 2.9.1. */ - virtual wxGraphicsBrush CreateLinearGradientBrush(wxDouble x1, - wxDouble y1, - wxDouble x2, - wxDouble y2, - const wxColour& c1, - const wxColour& c2) const; + //@{ + wxGraphicsBrush + CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxColour& c1, const wxColour& c2) const; + + wxGraphicsBrush + CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) const; + //@} /** Creates a native affine transformation matrix from the passed in @@ -391,15 +401,30 @@ public: virtual wxGraphicsPen CreatePen(const wxPen& pen) const; /** - Creates a native brush, having a radial gradient originating at - (@a xo, @a yc) with color @a oColour and ends on a circle around - (@a xc, @a yc) with the given @a radius and color @a cColour. + Creates a native brush with a radial gradient. + + The brush originats at (@a xo, @a yc) and ends on a circle around + (@a xc, @a yc) 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. */ - virtual wxGraphicsBrush CreateRadialGradientBrush(wxDouble xo, wxDouble yo, - wxDouble xc, wxDouble yc, - wxDouble radius, - const wxColour& oColor, - const wxColour& cColor) const; + //@{ + virtual wxGraphicsBrush + CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxColour& oColor, + const wxColour& cColor) const; + + virtual wxGraphicsBrush + CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops) = 0; + //@} /** Draws the bitmap. In case of a mono bitmap, this is treated as a mask @@ -611,39 +636,152 @@ public: virtual void Translate(wxDouble dx, wxDouble dy) = 0; /** - Redirects all rendering is done into a fully transparent temporary context + Redirects all rendering is done into a fully transparent temporary context */ virtual void BeginLayer(wxDouble opacity) = 0; - /** - Composites back the drawings into the context with the opacity given at + /** + Composites back the drawings into the context with the opacity given at the BeginLayer call */ virtual void EndLayer() = 0; - /** + /** Sets the antialiasing mode, returns true if it supported */ virtual bool SetAntialiasMode(wxAntialiasMode antialias) = 0; - /** + /** Returns the current shape antialiasing mode */ virtual wxAntialiasMode GetAntialiasMode() const ; - + /** Sets the compositing operator, returns true if it supported */ virtual bool SetCompositionMode(wxCompositionMode op) = 0; - /** + /** Returns the current compositing operator */ virtual wxCompositionMode GetCompositionMode() const; - + +}; + +/** + Represents a single gradient stop in a collection of gradient stops as + represented by wxGraphicsGradientStops. + + @library{wxcore} + @category{gdi} + + @since 2.9.1 +*/ +class wxGraphicsGradientStop +{ +public: + /** + Creates a stop with the given colour and position. + + @param col The colour of this stop. Note that the alpha component of + the colour is honoured thus allowing the background colours to + partially show through the gradient. + @param pos The stop position, must be in [0, 1) range with 0 being the + beginning and 1 the end of the gradient (but it doesn't make sense + to create a stop at position 1 because it would never be visible + anyhow). + */ + wxGraphicsGradientStop(wxColour col, float pos); + + /// Return the stop colour. + const wxColour& GetColour() const; + + /** + Change the stop colour. + + @param col The new colour. + */ + void SetColour(const wxColour& col); + + /// Return the stop position. + float GetPosition() const; + + /** + Change the stop position. + + @param pos The new position, must always be in [0, 1) range. + */ + void SetPosition(float pos); }; +/** + Represents a collection of wxGraphicGradientStop values for use with + CreateLinearGradientBrush and CreateRadialGradientBrush. + + The stops are maintained in order of position. If two or more stops are + added with the same position then the one(s) added later come later. + This can be useful for producing discontinuities in the colour gradient. + + Notice that this class is write-once, you can't modify the stops once they + had been added. + + @library{wxcore} + @category{gdi} + + @since 2.9.1 +*/ +class wxGraphicsGradientStops +{ +public: + /** + Initializes the gradient stops with the given boundary colours. + + Creates a wxGraphicsGradientStops instance with start colour given + by @a startCol and end colour given by @a endCol. + */ + wxGraphicsGradientStops(wxColour startCol = wxTransparentColour, + wxColour endCol = wxTransparentColour); + /** + Add a new stop. + */ + //@{ + void Add(const wxGraphicsGradientStop& stop); + void Add(wxColour col, float pos); + //@} + + /** + Returns the stop at the given index. + + @param n The index, must be in [0, GetCount()) range. + */ + wxGraphicsGradientStop Item(unsigned n) const; + + /** + Returns the number of stops. + */ + unsigned GetCount() const; + + /** + Set the start colour to @a col + */ + void SetStartColour(wxColour col); + + /** + Returns the start colour. + */ + wxColour GetStartColour() const; + + /** + Set the end colour to @a col + */ + void SetEndColour(wxColour col); + + /** + Returns the end colour. + */ + wxColour GetEndColour() const; +}; /** @class wxGraphicsRenderer @@ -707,7 +845,7 @@ public: virtual wxGraphicsContext* CreateContextFromNativeWindow(void* window) = 0; /** - Creates a wxGraphicsContext that can be used for measuring texts only. + Creates a wxGraphicsContext that can be used for measuring texts only. No drawing commands are allowed. */ virtual wxGraphicsContext * CreateMeasuringContext() = 0; @@ -718,16 +856,18 @@ public: virtual wxGraphicsFont CreateFont(const wxFont& font, const wxColour& col = *wxBLACK) = 0; + /** - Creates a native brush, having a linear gradient, starting at - (@a x1, @a y1) with color @a c1 to (@a x2, @a y2) with color @a c2. + Creates a native brush with a linear gradient. + + Stops support is new since wxWidgets 2.9.1, previously only the start + and end colours could be specified. */ virtual wxGraphicsBrush CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour& c1, - const wxColour& c2) = 0; + const wxGraphicsGradientStops& stops) = 0; /** Creates a native affine transformation matrix from the passed in @@ -749,15 +889,15 @@ public: virtual wxGraphicsPen CreatePen(const wxPen& pen) = 0; /** - Creates a native brush, having a radial gradient originating at - (@a xo, @a yc) with color @a oColour and ends on a circle around - (@a xc, @a yc) with the given @a radius and color @a cColour. + Creates a native brush with a radial gradient. + + Stops support is new since wxWidgets 2.9.1, previously only the start + and end colours could be specified. */ virtual wxGraphicsBrush CreateRadialGradientBrush(wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour& oColour, - const wxColour& cColour) = 0; + const wxGraphicsGradientStops& stops) = 0; /** Returns the default renderer on this platform. On OS X this is the Core diff --git a/samples/drawing/drawing.cpp b/samples/drawing/drawing.cpp index 5069eb5938..2e2084b62b 100644 --- a/samples/drawing/drawing.cpp +++ b/samples/drawing/drawing.cpp @@ -955,7 +955,7 @@ void MyCanvas::DrawGraphics(wxGraphicsContext* gc) { wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); gc->SetFont(font,*wxBLACK); - + // make a path that contains a circle and some lines, centered at 0,0 wxGraphicsPath path = gc->CreatePath() ; path.AddCircle( 0, 0, BASE2 ); @@ -965,14 +965,14 @@ void MyCanvas::DrawGraphics(wxGraphicsContext* gc) path.AddLineToPoint(BASE2, 0); path.CloseSubpath(); path.AddRectangle(-BASE4, -BASE4/2, BASE2, BASE4); - + // Now use that path to demonstrate various capbilites of the grpahics context - gc->PushState(); // save current translation/scale/other state + gc->PushState(); // save current translation/scale/other state gc->Translate(60, 75); // reposition the context origin gc->SetPen(wxPen("navy", 1)); gc->SetBrush(wxBrush("pink")); - + for( int i = 0 ; i < 3 ; ++i ) { wxString label; @@ -1005,11 +1005,11 @@ void MyCanvas::DrawGraphics(wxGraphicsContext* gc) } gc->Translate(2*BASE, 0); } - + gc->PopState(); // restore saved state gc->PushState(); // save it again gc->Translate(60, 200); // offset to the lower part of the window - + gc->DrawText("Scale", 0, -BASE2); gc->Translate(0, 20); @@ -1017,14 +1017,14 @@ void MyCanvas::DrawGraphics(wxGraphicsContext* gc) for( int i = 0 ; i < 8 ; ++i ) { gc->Scale(1.08, 1.08); // increase scale by 8% - gc->Translate(5,5); + gc->Translate(5,5); gc->DrawPath(path); } gc->PopState(); // restore saved state gc->PushState(); // save it again - gc->Translate(400, 200); - + gc->Translate(400, 200); + gc->DrawText("Rotate", 0, -BASE2); // Move the origin over to the next location @@ -1034,16 +1034,16 @@ void MyCanvas::DrawGraphics(wxGraphicsContext* gc) // and changing colors as we go for ( int angle = 0 ; angle < 360 ; angle += 30 ) { - gc->PushState(); // save this new current state so we can + gc->PushState(); // save this new current state so we can // pop back to it at the end of the loop wxImage::RGBValue val = wxImage::HSVtoRGB(wxImage::HSVValue(float(angle)/360, 1, 1)); gc->SetBrush(wxBrush(wxColour(val.red, val.green, val.blue, 64))); gc->SetPen(wxPen(wxColour(val.red, val.green, val.blue, 128))); - + // use translate to artfully reposition each drawn path gc->Translate(1.5 * BASE2 * cos(DegToRad(angle)), 1.5 * BASE2 * sin(DegToRad(angle))); - + // use Rotate to rotate the path gc->Rotate(DegToRad(angle)); @@ -1231,6 +1231,7 @@ void MyCanvas::DrawGradients(wxDC& dc) r.Offset(0, TEXT_HEIGHT); dc.GradientFillLinear(r, *wxWHITE, *wxBLUE, wxUP); + wxRect gfr = wxRect(r); // RHS: concentric r = wxRect(200, 10, 50, 50); @@ -1283,6 +1284,127 @@ void MyCanvas::DrawGradients(wxDC& dc) dc.DrawRectangle(r4); r4.Deflate(1); dc.GradientFillLinear(r4, wxColour(0,0,0), wxColour(0,255,0), wxWEST); + +#if wxUSE_GRAPHICS_CONTEXT + if (m_useContext) + { + wxGCDC &gdc = (wxGCDC&)dc; + wxGraphicsContext *gc = gdc.GetGraphicsContext(); + wxGraphicsPath pth; + wxGraphicsGradientStops stops; + + gfr.Offset(0, gfr.height + 10); + dc.DrawText(wxT("Linear Gradient with Stops"), gfr.x, gfr.y); + gfr.Offset(0, TEXT_HEIGHT); + + stops = wxGraphicsGradientStops(wxColour(255,0,0), wxColour(0,0,255)); + stops.Add(wxColour(255,255,0), 0.33f); + stops.Add(wxColour(0,255,0), 0.67f); + + gc->SetBrush(gc->CreateLinearGradientBrush(gfr.x, gfr.y, + gfr.x + gfr.width, gfr.y + gfr.height, + stops)); + pth = gc->CreatePath(); + pth.MoveToPoint(gfr.x,gfr.y); + pth.AddLineToPoint(gfr.x + gfr.width,gfr.y); + pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height); + pth.AddLineToPoint(gfr.x,gfr.y+gfr.height); + pth.CloseSubpath(); + gc->FillPath(pth); + + gfr.Offset(0, gfr.height + 10); + dc.DrawText(wxT("Radial Gradient with Stops"), gfr.x, gfr.y); + gfr.Offset(0, TEXT_HEIGHT); + + gc->SetBrush(gc->CreateRadialGradientBrush(gfr.x + gfr.width / 2, + gfr.y + gfr.height / 2, + gfr.x + gfr.width / 2, + gfr.y + gfr.height / 2, + gfr.width / 2, + stops)); + pth = gc->CreatePath(); + pth.MoveToPoint(gfr.x,gfr.y); + pth.AddLineToPoint(gfr.x + gfr.width,gfr.y); + pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height); + pth.AddLineToPoint(gfr.x,gfr.y+gfr.height); + pth.CloseSubpath(); + gc->FillPath(pth); + + gfr.Offset(0, gfr.height + 10); + dc.DrawText(wxT("Linear Gradient with Stops and Gaps"), gfr.x, gfr.y); + gfr.Offset(0, TEXT_HEIGHT); + + stops = wxGraphicsGradientStops(wxColour(255,0,0), wxColour(0,0,255)); + stops.Add(wxColour(255,255,0), 0.33f); + stops.Add(wxTransparentColour, 0.33f); + stops.Add(wxTransparentColour, 0.67f); + stops.Add(wxColour(0,255,0), 0.67f); + + gc->SetBrush(gc->CreateLinearGradientBrush(gfr.x, gfr.y + gfr.height, + gfr.x + gfr.width, gfr.y, + stops)); + pth = gc->CreatePath(); + pth.MoveToPoint(gfr.x,gfr.y); + pth.AddLineToPoint(gfr.x + gfr.width,gfr.y); + pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height); + pth.AddLineToPoint(gfr.x,gfr.y+gfr.height); + pth.CloseSubpath(); + gc->FillPath(pth); + + gfr.Offset(0, gfr.height + 10); + dc.DrawText(wxT("Radial Gradient with Stops and Gaps"), gfr.x, gfr.y); + gfr.Offset(0, TEXT_HEIGHT); + + gc->SetBrush(gc->CreateRadialGradientBrush(gfr.x + gfr.width / 2, + gfr.y + gfr.height / 2, + gfr.x + gfr.width / 2, + gfr.y + gfr.height / 2, + gfr.width / 2, + stops)); + pth = gc->CreatePath(); + pth.MoveToPoint(gfr.x,gfr.y); + pth.AddLineToPoint(gfr.x + gfr.width,gfr.y); + pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height); + pth.AddLineToPoint(gfr.x,gfr.y+gfr.height); + pth.CloseSubpath(); + gc->FillPath(pth); + + gfr.Offset(0, gfr.height + 10); + dc.DrawText(wxT("Gradients with Stops and Transparency"), gfr.x, gfr.y); + gfr.Offset(0, TEXT_HEIGHT); + + stops = wxGraphicsGradientStops(wxColour(255,0,0), wxTransparentColour); + stops.Add(wxColour(255,0,0), 0.33f); + stops.Add(wxTransparentColour, 0.33f); + stops.Add(wxTransparentColour, 0.67f); + stops.Add(wxColour(0,0,255), 0.67f); + stops.Add(wxColour(0,0,255), 1.0f); + + pth = gc->CreatePath(); + pth.MoveToPoint(gfr.x,gfr.y); + pth.AddLineToPoint(gfr.x + gfr.width,gfr.y); + pth.AddLineToPoint(gfr.x + gfr.width,gfr.y+gfr.height); + pth.AddLineToPoint(gfr.x,gfr.y+gfr.height); + pth.CloseSubpath(); + + gc->SetBrush(gc->CreateRadialGradientBrush(gfr.x + gfr.width / 2, + gfr.y + gfr.height / 2, + gfr.x + gfr.width / 2, + gfr.y + gfr.height / 2, + gfr.width / 2, + stops)); + gc->FillPath(pth); + + stops = wxGraphicsGradientStops(wxColour(255,0,0, 128), wxColour(0,0,255, 128)); + stops.Add(wxColour(255,255,0,128), 0.33f); + stops.Add(wxColour(0,255,0,128), 0.67f); + + gc->SetBrush(gc->CreateLinearGradientBrush(gfr.x, gfr.y, + gfr.x + gfr.width, gfr.y, + stops)); + gc->FillPath(pth); + } +#endif // wxUSE_GRAPHICS_CONTEXT } void MyCanvas::DrawRegions(wxDC& dc) @@ -1474,7 +1596,7 @@ void MyCanvas::OnMouseMove(wxMouseEvent &event) str.Printf( wxT("Current mouse position: %d,%d"), (int)x, (int)y ); m_owner->SetStatusText( str ); } - + if ( m_rubberBand ) { int x,y, xx, yy ; @@ -1504,8 +1626,8 @@ void MyCanvas::OnMouseMove(wxMouseEvent &event) void MyCanvas::OnMouseDown(wxMouseEvent &event) { - int x,y,xx,yy ; - event.GetPosition(&x,&y); + int x,y,xx,yy ; + event.GetPosition(&x,&y); CalcUnscrolledPosition( x, y, &xx, &yy ); m_anchorpoint = wxPoint( xx , yy ) ; m_currentpoint = m_anchorpoint ; @@ -1530,9 +1652,9 @@ void MyCanvas::OnMouseUp(wxMouseEvent &event) int x,y,xx,yy ; event.GetPosition(&x,&y); CalcUnscrolledPosition( x, y, &xx, &yy ); - + wxString str; - str.Printf( wxT("Rectangle selection from %d,%d to %d,%d"), + str.Printf( wxT("Rectangle selection from %d,%d to %d,%d"), m_anchorpoint.x, m_anchorpoint.y , (int)xx, (int)yy ); wxMessageBox( str , wxT("Rubber-Banding") ); @@ -1658,8 +1780,8 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) m_xAxisReversed = m_yAxisReversed = false; m_backgroundMode = wxSOLID; - m_colourForeground = *wxRED; - m_colourBackground = *wxBLUE; + m_colourForeground = *wxBLACK; + m_colourBackground = *wxLIGHT_GREY; m_textureBackground = false; m_canvas = new MyCanvas( this ); diff --git a/src/common/graphcmn.cpp b/src/common/graphcmn.cpp index dcdf8485e3..b014460e0b 100644 --- a/src/common/graphcmn.cpp +++ b/src/common/graphcmn.cpp @@ -489,6 +489,41 @@ void wxGraphicsPathData::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, AddLineToPoint(p2.m_x,p2.m_y); } +//----------------------------------------------------------------------------- +// wxGraphicsGradientStops +//----------------------------------------------------------------------------- + +void wxGraphicsGradientStops::Add(const wxGraphicsGradientStop& stop) +{ + for ( wxVector::iterator it = m_stops.begin(); + it != m_stops.end(); + ++it ) + { + if ( stop.GetPosition() < it->GetPosition() ) + { + if ( it != m_stops.begin() ) + { + m_stops.insert(it, stop); + } + else // we shouldn't be inserting it at the beginning + { + wxFAIL_MSG( "invalid gradient stop position < 0" ); + } + + return; + } + } + + if ( stop.GetPosition() == 1. ) + { + m_stops.insert(m_stops.end() - 1, stop); + } + else + { + wxFAIL_MSG( "invalid gradient stop position >= 1" ); + } +} + //----------------------------------------------------------------------------- // wxGraphicsContext Convenience Methods //----------------------------------------------------------------------------- @@ -753,19 +788,55 @@ wxGraphicsBrush wxGraphicsContext::CreateBrush(const wxBrush& brush ) const return GetRenderer()->CreateBrush(brush); } -// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 -wxGraphicsBrush wxGraphicsContext::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) const +wxGraphicsBrush +wxGraphicsContext::CreateLinearGradientBrush( + wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxColour& c1, const wxColour& c2) const +{ + return GetRenderer()->CreateLinearGradientBrush + ( + x1, y1, + x2, y2, + wxGraphicsGradientStops(c1,c2) + ); +} + +wxGraphicsBrush +wxGraphicsContext::CreateLinearGradientBrush( + wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& gradientStops) 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()->CreateLinearGradientBrush(x1,y1,x2,y2,c1,c2); + return GetRenderer()->CreateRadialGradientBrush + ( + xo, yo, + xc, yc, radius, + wxGraphicsGradientStops(oColor, cColor) + ); } -// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) -// with radius r and color cColor -wxGraphicsBrush wxGraphicsContext::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) const +wxGraphicsBrush +wxGraphicsContext::CreateRadialGradientBrush( + wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, wxDouble radius, + const wxGraphicsGradientStops& gradientStops) const { - return GetRenderer()->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); + return GetRenderer()->CreateRadialGradientBrush + ( + xo, yo, + xc, yc, radius, + gradientStops + ); } // sets the font diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index 2767ab8c19..c832f18361 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -248,14 +248,20 @@ public: ~wxCairoBrushData (); virtual void Apply( wxGraphicsContext* context ); - void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2 ); - void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor ); + + 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: virtual void Init(); + // common part of Create{Linear,Radial}GradientBrush() + void AddGradientStops(const wxGraphicsGradientStops& stops); + private : double m_red; double m_green; @@ -683,26 +689,50 @@ void wxCairoBrushData::Apply( wxGraphicsContext* context ) } } -void wxCairoBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2 ) +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_brushPattern, + stop.GetPosition(), + col.Red()/255.0, + col.Green()/255.0, + col.Blue()/255.0, + col.Alpha()/255.0 + ); + } + + wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, + wxT("Couldn't create cairo pattern")); +} + +void +wxCairoBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) { m_brushPattern = cairo_pattern_create_linear(x1,y1,x2,y2); - cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,c1.Red()/255.0, - c1.Green()/255.0, c1.Blue()/255.0,c1.Alpha()/255.0); - cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,c2.Red()/255.0, - c2.Green()/255.0, c2.Blue()/255.0,c2.Alpha()/255.0); - wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern")); + + AddGradientStops(stops); } -void wxCairoBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor ) +void +wxCairoBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops) { m_brushPattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius); - cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,oColor.Red()/255.0, - oColor.Green()/255.0, oColor.Blue()/255.0,oColor.Alpha()/255.0); - cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,cColor.Red()/255.0, - cColor.Green()/255.0, cColor.Blue()/255.0,cColor.Alpha()/255.0); - wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern")); + + AddGradientStops(stops); } void wxCairoBrushData::Init() @@ -1113,10 +1143,10 @@ wxCairoBitmapData::~wxCairoBitmapData() { if (m_pattern) cairo_pattern_destroy(m_pattern); - + if (m_surface) cairo_surface_destroy(m_surface); - + delete [] m_buffer; } @@ -1735,14 +1765,16 @@ public : virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ; - // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 - virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) ; + virtual wxGraphicsBrush + CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops); - // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) - // with radius r and color cColor - virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) ; + virtual wxGraphicsBrush + CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops); // sets the font virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ; @@ -1874,25 +1906,26 @@ wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush ) } } -// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 -wxGraphicsBrush wxCairoRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) +wxGraphicsBrush +wxCairoRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) { wxGraphicsBrush p; wxCairoBrushData* d = new wxCairoBrushData( this ); - d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2); + d->CreateLinearGradientBrush(x1, y1, x2, y2, stops); p.SetRefData(d); return p; } -// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) -// with radius r and color cColor -wxGraphicsBrush wxCairoRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) +wxGraphicsBrush +wxCairoRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, wxDouble r, + const wxGraphicsGradientStops& stops) { wxGraphicsBrush p; wxCairoBrushData* d = new wxCairoBrushData( this ); - d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); + d->CreateRadialGradientBrush(xo, yo, xc, yc, r, stops); p.SetRefData(d); return p; } diff --git a/src/msw/graphics.cpp b/src/msw/graphics.cpp index f1cab063cd..8eb6374851 100644 --- a/src/msw/graphics.cpp +++ b/src/msw/graphics.cpp @@ -246,16 +246,24 @@ public: wxGDIPlusBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush ); ~wxGDIPlusBrushData (); - void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2 ); - void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor ); + 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 Brush* GetGDIPlusBrush() { return m_brush; } protected: virtual void Init(); -private : +private: + // common part of Create{Linear,Radial}GradientBrush() + template + void SetGradientStops(T *brush, const wxGraphicsGradientStops& stops); + Brush* m_brush; Image* m_brushImage; GraphicsPath* m_brushPath; @@ -628,28 +636,67 @@ void wxGDIPlusBrushData::Init() m_brushPath= NULL; } -void wxGDIPlusBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2) +template +void +wxGDIPlusBrushData::SetGradientStops(T *brush, + const wxGraphicsGradientStops& stops) +{ + 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); + + 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) { - m_brush = new LinearGradientBrush( PointF( x1,y1) , PointF( x2,y2), - Color( c1.Alpha(), c1.Red(),c1.Green() , c1.Blue() ), - Color( c2.Alpha(), c2.Red(),c2.Green() , c2.Blue() )); + 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 wxColour &oColor, const wxColour &cColor) +void +wxGDIPlusBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops) { - // Create a path that consists of a single circle. m_brushPath = new GraphicsPath(); - m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius), (REAL)(2*radius), (REAL)(2*radius)); + m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius), + (REAL)(2*radius), (REAL)(2*radius)); - PathGradientBrush *b = new PathGradientBrush(m_brushPath); - m_brush = b; - b->SetCenterPoint( PointF(xo,yo)); - b->SetCenterColor(Color( oColor.Alpha(), oColor.Red(),oColor.Green() , oColor.Blue() )); + PathGradientBrush * const brush = new PathGradientBrush(m_brushPath); + m_brush = brush; + brush->SetCenterPoint(PointF(xo, yo)); + brush->SetCenterColor(wxColourToColor(stops.GetStartColour())); - Color colors[] = {Color( cColor.Alpha(), cColor.Red(),cColor.Green() , cColor.Blue() )}; + const Color col(wxColourToColor(stops.GetEndColour())); int count = 1; - b->SetSurroundColors(colors, &count); + brush->SetSurroundColors(&col, &count); + + SetGradientStops(brush, stops); } //----------------------------------------------------------------------------- @@ -1596,15 +1643,16 @@ public : virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ; - // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 - virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) ; - - // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) - // with radius r and color cColor - virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) ; + virtual wxGraphicsBrush + CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops); + virtual wxGraphicsBrush + CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops); // sets the font virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ; @@ -1613,7 +1661,7 @@ public : // create a graphics bitmap from a native bitmap virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap( void* bitmap ); - + // create a subimage from a native image representation virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); @@ -1789,27 +1837,29 @@ wxGraphicsBrush wxGDIPlusRenderer::CreateBrush(const wxBrush& brush ) } } -// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 -wxGraphicsBrush wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) +wxGraphicsBrush +wxGDIPlusRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) { ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush); wxGraphicsBrush p; wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this ); - d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2); + d->CreateLinearGradientBrush(x1, y1, x2, y2, stops); p.SetRefData(d); return p; } -// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) -// with radius r and color cColor -wxGraphicsBrush wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) +wxGraphicsBrush +wxGDIPlusRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops) { ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush); wxGraphicsBrush p; wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this ); - d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); + d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,stops); p.SetRefData(d); return p; } diff --git a/src/osx/carbon/graphics.cpp b/src/osx/carbon/graphics.cpp index 99e1921ebf..75f74d7de8 100644 --- a/src/osx/carbon/graphics.cpp +++ b/src/osx/carbon/graphics.cpp @@ -666,15 +666,18 @@ public: ~wxMacCoreGraphicsBrushData (); virtual void Apply( wxGraphicsContext* context ); - void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2 ); - void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor ); + 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 wxColour& c1, const wxColour& c2 ); + CGFunctionRef CreateGradientFunction(const wxGraphicsGradientStops& stops); + static void CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out); virtual void Init(); @@ -691,19 +694,24 @@ wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData( wxGraphicsRenderer* rend Init(); } -void wxMacCoreGraphicsBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2 ) +void +wxMacCoreGraphicsBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) { - m_gradientFunction = CreateGradientFunction( c1, c2 ); + 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 wxColour &oColor, const wxColour &cColor ) +void +wxMacCoreGraphicsBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops) { - m_gradientFunction = CreateGradientFunction( oColor, cColor ); + 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 ; @@ -759,8 +767,13 @@ void wxMacCoreGraphicsBrushData::CalculateShadingValues (void *info, const CGFlo } } -CGFunctionRef wxMacCoreGraphicsBrushData::CreateGradientFunction( const wxColour& c1, const wxColour& c2 ) +CGFunctionRef +wxMacCoreGraphicsBrushData::CreateGradientFunction(const wxGraphicsGradientStops& stops) { + // TODO: implement support for intermediate gradient stops + const wxColour c1 = stops.GetStartColour(); + const wxColour c2 = stops.GetEndColour(); + 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 }; @@ -1138,7 +1151,7 @@ public : // appends a rectangle as a new closed subpath virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ); - // appends a circle as a new closed subpath + // appends a circle as a new closed subpath virtual void AddCircle( wxDouble x, wxDouble y, wxDouble r ); // appends an ellipsis as a new closed subpath fitting the passed rectangle @@ -2618,14 +2631,16 @@ public : virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ; - // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 - virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) ; + virtual wxGraphicsBrush + CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops); - // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) - // with radius r and color cColor - virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) ; + virtual wxGraphicsBrush + CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops); // sets the font virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ; @@ -2819,25 +2834,27 @@ wxGraphicsBitmap wxMacCoreGraphicsRenderer::CreateSubBitmap( const wxGraphicsBit return wxNullGraphicsBitmap; } -// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 -wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) +wxGraphicsBrush +wxMacCoreGraphicsRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) { wxGraphicsBrush p; wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this ); - d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2); + d->CreateLinearGradientBrush(x1, y1, x2, y2, stops); p.SetRefData(d); return p; } -// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) -// with radius r and color cColor -wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) +wxGraphicsBrush +wxMacCoreGraphicsRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops) { wxGraphicsBrush p; wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this ); - d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); + d->CreateRadialGradientBrush(xo, yo, xc, yc, radius, stops); p.SetRefData(d); return p; }