public void Render( IGraphCanvas graphics, GraphTransform transform, IGraph2dSource data, PointF cursorDataPt, bool enabled )
 {
     foreach ( IGraph2dRenderer renderer in m_Renderers )
     {
         renderer.Render( graphics, transform, data, cursorDataPt, enabled );
     }
 }
        /// <summary>
        /// Renders graph data
        /// </summary>
        /// <param name="graphics">Graphics object to render into</param>
        /// <param name="transform">Graph transform</param>
        /// <param name="data">Data to render</param>
        /// <param name="cursorDataPt">Position of the mouse cursor in data space</param>
        /// <param name="enabled">The enabled state of the graph control</param>
        public void Render( IGraphCanvas graphics, GraphTransform transform, IGraph2dSource data, PointF cursorDataPt, bool enabled )
        {
            IGraphX2dSampleSource sampleSource = ( IGraphX2dSampleSource )data;

            int sample = ( int )( transform.DataBounds.Left / sampleSource.XStepPerSample );
            Color darkColour = GraphUtils.ScaleColour( m_Colour, 0.2f );
            float hStep = sampleSource.XStepPerSample / 2;
            float dataX = ( sample * sampleSource.XStepPerSample ) + hStep;
            while ( dataX < transform.DataBounds.Right )
            {
                float value = sampleSource.Evaluate( dataX );
                dataX += sampleSource.XStepPerSample;

                Point tl = transform.DataToScreen( new PointF( dataX - hStep, value ) );
                Point br = transform.DataToScreen( new PointF( dataX + hStep, 0 ) );
                if ( ( br.Y - tl.Y ) == 0 )
                {
                    continue;
                }

                Rectangle barArea = new Rectangle( tl.X - 1, tl.Y, ( br.X - tl.X ) + 1, br.Y - tl.Y );
                using ( LinearGradientBrush brush = new LinearGradientBrush( barArea, m_Colour, darkColour, 90.0f ) )
                {
                    brush.InterpolationColors = m_Blends;
                    graphics.FillRectangle( brush, barArea );
                }
            }
        }
        /// <summary>
        /// Renders a graph using this renderer
        /// </summary>
        public void Render( IGraphCanvas graphics, GraphTransform transform, IGraph2dSource data, PointF cursorDataPt, bool enabled )
        {
            Graph2dSourceUniformValue uniformData = ( Graph2dSourceUniformValue )data;

            if ( uniformData.FixedAxis == Graph2dSourceUniformValue.Axis.X )
            {
                float dataX = transform.DataToScreen( new PointF( uniformData.Value, 0 ) ).X;

                //	TODO: Need to
                if ( Math.Abs( cursorDataPt.X - uniformData.Value ) < transform.ScreenToDataXScale * Graph2dUniformValueController.ScreenSelectionTolerance )
                {
                    graphics.DrawLine( s_HighlightPen, dataX, transform.DrawBounds.Top, dataX, transform.DrawBounds.Bottom );
                }
                graphics.DrawLine( m_Pen, dataX, transform.DrawBounds.Top, dataX, transform.DrawBounds.Bottom );

            }
            else
            {
                float dataY = transform.DataToScreen( new PointF( 0, uniformData.Value ) ).Y;
                if ( Math.Abs( cursorDataPt.Y - uniformData.Value ) < transform.ScreenToDataYScale * Graph2dUniformValueController.ScreenSelectionTolerance )
                {
                    graphics.DrawLine( s_HighlightPen, transform.DrawBounds.Left, dataY, transform.DrawBounds.Right, dataY );
                }
                graphics.DrawLine( m_Pen, transform.DrawBounds.Left, dataY, transform.DrawBounds.Right, dataY );

            }
        }
        /// <summary>
        /// Called by the control owner when the left mouse button is pressed
        /// </summary>
        /// <param name="data">Graph data</param>
        /// <param name="transform">Graph view transform</param>
        /// <param name="dataX">Mouse X position in data space</param>
        /// <param name="dataY">Mouse Y position in data space</param>
        /// <param name="down">True if the button was pressed, false if the button was released</param>
        /// <returns>Returns true if the event was handled, and the control owner should perform no further processing</returns>
        public override bool OnMouseLeftButton( IGraph2dSource data, GraphTransform transform, float dataX, float dataY, bool down )
        {
            if ( !down || data.Disabled )
            {
                m_MovingIndices = null;
                return false;
            }

            GraphX2dSourceFunction1dAdapter pwlData = ( GraphX2dSourceFunction1dAdapter )data;
            PiecewiseLinearFunction1d pwlFunc = ( PiecewiseLinearFunction1d )pwlData.Function;

            float selectionDistance = transform.ScreenToDataYScale * ScreenSelectionTolerance;
            int closestCpIndex = pwlFunc.FindControlPoint( new Point2(  dataX, dataY ), selectionDistance );
            if ( closestCpIndex != -1 )
            {
                m_MovingIndices = new int[] { closestCpIndex };
                return true;
            }

            int closestCp0;
            int closestCp1;
            if ( GetLineNear( pwlFunc, new Point2( dataX, dataY ), out closestCp0, out closestCp1, selectionDistance ) )
            {
                m_MovingIndices = new int[] { closestCp0, closestCp1 };
                return true;
            }
            return false;
        }
        /// <summary>
        /// Called by the control owner when the left mouse button is pressed
        /// </summary>
        /// <param name="data">Graph data</param>
        /// <param name="transform">Graph view transform</param>
        /// <param name="dataX">Mouse X position in data space</param>
        /// <param name="dataY">Mouse Y position in data space</param>
        /// <param name="down">True if the button was pressed, false if the button was released</param>
        /// <returns>Returns true if the event was handled, and the control owner should perform no further processing</returns>
        public override bool OnMouseLeftButton( IGraph2dSource data, GraphTransform transform, float dataX, float dataY, bool down )
        {
            if ( !down || data.Disabled )
            {
                m_Moving = false;
                return false;
            }
            float selectionDistance = transform.ScreenToDataYScale * ScreenSelectionTolerance;

            Graph2dSourceUniformValue uniformData = (Graph2dSourceUniformValue)data;
            float value = uniformData.FixedAxis == Graph2dSourceUniformValue.Axis.X ? dataX : dataY;
            m_Moving = Math.Abs( value - uniformData.Value ) < selectionDistance;

            return false;
        }
        /// <summary>
        /// Called by the control owner when the mouse is moved
        /// </summary>
        /// <param name="data">Graph data</param>
        /// <param name="transform">Graph view transform</param>
        /// <param name="lastDataX">Previous mouse X position in data space</param>
        /// <param name="lastDataY">Previous mouse Y position in data space</param>
        /// <param name="dataX">Mouse X position in data space</param>
        /// <param name="dataY">Mouse Y position in data space</param>
        /// <returns>Returns true if the event was handled, and the control owner should perform no further processing</returns>
        public override bool OnMouseMove( IGraph2dSource data, GraphTransform transform, float lastDataX, float lastDataY, float dataX, float dataY )
        {
            if ( data.Disabled || !m_Moving )
            {
                return false;
            }

            Graph2dSourceUniformValue uniformData = ( Graph2dSourceUniformValue )data;
            if ( uniformData.FixedAxis == Graph2dSourceUniformValue.Axis.X )
            {
                uniformData.Value += dataX - lastDataX;
            }
            else
            {
                uniformData.Value += dataY - lastDataY;
            }

            return false;
        }
        /// <summary>
        /// Renders the graph
        /// </summary>
        public void Render( IGraphCanvas graphics, GraphTransform transform, IGraph2dSource data, PointF cursorDataPt, bool enabled )
        {
            Pen pen = ( enabled && !data.Disabled ) ? m_Pen : s_DisabledPen;
            Pen shadowPen = GetShadowPen( data );

            GraphX2dSourceFunction1dAdapter cpData = ( GraphX2dSourceFunction1dAdapter )data;
            PiecewiseLinearFunction1d pwl = ( PiecewiseLinearFunction1d )cpData.Function;

            float tolerance = transform.ScreenToDataYScale * GraphX2dControlPointController.ScreenSelectionTolerance;
            int highlightCpIndex = IndexOfControlPointNearPoint( pwl.ControlPoints, new Point2( cursorDataPt.X, cursorDataPt.Y ), tolerance );

            Point2 cp = pwl[ 0 ];
            Point lastPt = transform.DataToScreen( new PointF( cp.X, cp.Y ) );
            if ( NoEndPoints )
            {
                Point edgePt = transform.DataToScreen( new PointF( transform.DataBounds.Left, cp.Y ) );
                DrawGraphLine( graphics, pen, shadowPen, enabled, lastPt, edgePt );
            }

            for ( int cpIndex = 1; cpIndex < pwl.NumControlPoints; ++cpIndex )
            {
                cp = pwl[ cpIndex ];
                Point pt = transform.DataToScreen( new PointF( cp.X, cp.Y ) );

                DrawGraphLine( graphics, pen, shadowPen, enabled, lastPt, pt );
                DrawControlPoint( graphics, lastPt, enabled ? m_Brush : s_DisabledBrush, highlightCpIndex == ( cpIndex - 1 ) );

                lastPt = pt;
            }

            if ( NoEndPoints )
            {
                Point edgePt = transform.DataToScreen( new PointF( transform.DataBounds.Right, cp.Y ) );
                DrawGraphLine( graphics, pen, shadowPen, enabled, lastPt, edgePt );
            }
            DrawControlPoint( graphics, lastPt, Brushes.Blue, highlightCpIndex == ( pwl.NumControlPoints - 1 ) );
        }
        /// <summary>
        /// Renders control points in a graph that derives from Graph2dPiecewiseLinear
        /// </summary>
        public void Render( IGraphCanvas graphics, GraphTransform transform, IGraph2dSource data, PointF cursorDataPt, bool enabled )
        {
            if ( data.Disabled )
            {
                return;
            }
            GraphX2dSourceFunction1dAdapter pwlGraph = ( GraphX2dSourceFunction1dAdapter )data;
            PiecewiseLinearFunction1d pwlFunc = ( PiecewiseLinearFunction1d )pwlGraph.Function;

            float tolerance = transform.ScreenToDataYScale * GraphX2dControlPointController.ScreenSelectionTolerance;
            int highlightCpIndex = pwlFunc.FindControlPoint( new Point2( cursorDataPt.X, cursorDataPt.Y ), tolerance );

            for ( int cpIndex = 0; cpIndex < pwlFunc.NumControlPoints; ++cpIndex )
            {
                Point2 cp = pwlFunc[ cpIndex ];
                PointF screenPt = transform.DataToScreen( new PointF( cp.X, cp.Y ) );
                graphics.FillCircle( m_CpBrush, screenPt.X, screenPt.Y, 2 );

                if ( cpIndex == highlightCpIndex )
                {
                    graphics.DrawCircle( s_HighlightPen, screenPt.X, screenPt.Y, 4 );
                }
            }
        }
 /// <summary>
 /// Called by the control owner when the right mouse button is pressed
 /// </summary>
 /// <param name="data">Graph data</param>
 /// <param name="transform">Graph view transform</param>
 /// <param name="dataX">Mouse X position in data space</param>
 /// <param name="dataY">Mouse Y position in data space</param>
 /// <param name="down">True if the button was pressed, false if the button was released</param>
 /// <returns>Returns true if the event was handled, and the control owner should perform no further processing</returns>
 public virtual bool OnMouseRightButton( IGraph2dSource data, GraphTransform transform, float dataX, float dataY, bool down )
 {
     return false;
 }
 /// <summary>
 /// Called by the control owner when the mouse is moved
 /// </summary>
 /// <param name="data">Graph data</param>
 /// <param name="transform">Graph view transform</param>
 /// <param name="lastDataX">Previous mouse X position in data space</param>
 /// <param name="lastDataY">Previous mouse Y position in data space</param>
 /// <param name="dataX">Mouse X position in data space</param>
 /// <param name="dataY">Mouse Y position in data space</param>
 /// <returns>Returns true if the event was handled, and the control owner should perform no further processing</returns>
 public virtual bool OnMouseMove( IGraph2dSource data, GraphTransform transform, float lastDataX, float lastDataY, float dataX, float dataY )
 {
     return false;
 }
        /// <summary>
        /// Called by the control owner when the mouse is moved
        /// </summary>
        /// <param name="data">Graph data</param>
        /// <param name="transform">Graph view transform</param>
        /// <param name="lastDataX">Previous mouse X position in data space</param>
        /// <param name="lastDataY">Previous mouse Y position in data space</param>
        /// <param name="dataX">Mouse X position in data space</param>
        /// <param name="dataY">Mouse Y position in data space</param>
        /// <returns>Returns true if the event was handled, and the control owner should perform no further processing</returns>
        public override bool OnMouseMove( IGraph2dSource data, GraphTransform transform, float lastDataX, float lastDataY, float dataX, float dataY )
        {
            if ( data.Disabled || m_MovingIndices == null )
            {
                return false;
            }

            GraphX2dSourceFunction1dAdapter pwlData = ( GraphX2dSourceFunction1dAdapter )data;
            PiecewiseLinearFunction1d pwlFunc = ( PiecewiseLinearFunction1d )pwlData.Function;

            int lastCpIndex = pwlFunc.NumControlPoints - 1;
            foreach ( int cpIndex in m_MovingIndices )
            {
                if ( cpIndex == -1 )
                {
                    continue;
                }
                Point2 cp = pwlFunc[ cpIndex ];
                float deltaX = dataX - lastDataX;
                float deltaY = dataY - lastDataY;

                //	Clamp new control point (x,y) to the bounds of the data source
                float x = Rb.Core.Maths.Utils.Clamp( cp.X + deltaX, data.MinimumX, data.MaximumX );
                float y = Rb.Core.Maths.Utils.Clamp( cp.Y + deltaY, data.MinimumY, data.MaximumY );

                //	Clamp new control point x to the two neighbouring control points
                if ( ( cpIndex > 0 ) && ( x < pwlFunc[ cpIndex - 1 ].X ) )
                {
                    x = pwlFunc[ cpIndex - 1 ].X;
                }
                else if ( ( cpIndex < lastCpIndex ) && ( x > pwlFunc[ cpIndex + 1 ].X ) )
                {
                    x = pwlFunc[ cpIndex + 1 ].X;
                }

                pwlFunc[ cpIndex ] = new Point2( x, y );
            }

            return true;
        }
        /// <summary>
        /// Called by the control owner when the right mouse button is pressed
        /// </summary>
        /// <param name="data">Graph data</param>
        /// <param name="transform">Graph view transform</param>
        /// <param name="dataX">Mouse X position in data space</param>
        /// <param name="dataY">Mouse Y position in data space</param>
        /// <param name="down">True if the button was pressed, false if the button was released</param>
        /// <returns>Returns true if the event was handled, and the control owner should perform no further processing</returns>
        public override bool OnMouseRightButton( IGraph2dSource data, GraphTransform transform, float dataX, float dataY, bool down )
        {
            if ( !data.Selected || data.Disabled || !down )
            {
                return false;
            }

            GraphX2dSourceFunction1dAdapter pwlData = ( GraphX2dSourceFunction1dAdapter )data;
            PiecewiseLinearFunction1d pwlFunc = ( PiecewiseLinearFunction1d )pwlData.Function;
            int deleteIndex = pwlFunc.FindControlPoint( new Point2( dataX, dataY ), transform.ScreenToDataYScale * ScreenSelectionTolerance );
            if ( deleteIndex != -1 )
            {
                pwlFunc.RemoveControlPoint( deleteIndex );
                return false;
            }
            int insertAfterIndex = 0;
            for (; insertAfterIndex < pwlFunc.NumControlPoints; ++insertAfterIndex )
            {
                if ( dataX < pwlFunc[ insertAfterIndex ].X )
                {
                    break;
                }
            }

            pwlFunc.InsertControlPoint( insertAfterIndex, new Point2( dataX, dataY ) );

            return true;
        }
        /// <summary>
        /// Renders graph data
        /// </summary>
        /// <param name="graphics">Graphics object to render into</param>
        /// <param name="transform">Graph view transform</param>
        /// <param name="data">Data to render</param>
        /// <param name="cursorDataPt">Position of the mouse cursor in data space</param>
        /// <param name="enabled">The enabled state of the graph control</param>
        public virtual void Render( IGraphCanvas graphics, GraphTransform transform, IGraph2dSource data, PointF cursorDataPt, bool enabled )
        {
            IGraphX2dSource eval = ( IGraphX2dSource )data;
            Pen pen = ( enabled && !data.Disabled ) ? m_Pen : s_DisabledPen;

            Pen shadowPen = null;
            if ( !data.Disabled )
            {
                if ( data.Selected )
                {
                    shadowPen = s_SelectedPen;
                }
                else if ( data.Highlighted )
                {
                    shadowPen = s_HighlightedPen;
                }
            }

            float dataX = transform.DataBounds.Left;
            float dataXInc = transform.DataBounds.Width / transform.DrawBounds.Width;

            Point lastPt = transform.DataToScreen( new PointF( dataX, eval.Evaluate( dataX ) ) ) ;
            dataX += dataXInc;

            for ( int drawX = 1; drawX < transform.DrawBounds.Width; ++drawX, dataX += dataXInc )
            {
                Point pt = transform.DataToScreen( new PointF( dataX, eval.Evaluate( dataX ) ) );
                graphics.DrawLine( pen, lastPt.X, lastPt.Y, pt.X, pt.Y );
                if ( enabled && shadowPen != null )
                {
                    graphics.DrawLine( shadowPen, lastPt.X, lastPt.Y + 1, pt.X, pt.Y + 1 );
                    graphics.DrawLine( shadowPen, lastPt.X, lastPt.Y - 1, pt.X, pt.Y - 1 );
                }
                lastPt = pt;
            }
        }