StrokeCollection2.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Ink / StrokeCollection2.cs / 1305600 / StrokeCollection2.cs

                            //------------------------------------------------------------------------ 
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
//----------------------------------------------------------------------- 

using MS.Utility; 
using System; 
using System.ComponentModel;
using System.Collections; 
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Media; 
using System.Windows.Input;
using MS.Internal; 
using MS.Internal.Ink; 

using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;

namespace System.Windows.Ink
{ 

    ///  
    /// The hit-testing API of StrokeCollection. 
    /// 
    public partial class StrokeCollection : Collection, INotifyPropertyChanged, INotifyCollectionChanged 
    {
        #region Public APIs

        ///  
        /// Calculates the combined bounds of all strokes in the collection
        ///  
        ///  
        public Rect GetBounds()
        { 
            Rect bounds = Rect.Empty;
            foreach (Stroke stroke in this)
            {
                // samgeo - Presharp issue 
                // Presharp gives a warning when get methods might deref a null.  It's complaining
                // here that 'stroke'' could be null, but StrokeCollection never allows nulls to be added 
                // so this is not possible 
#pragma warning disable 1634, 1691
#pragma warning suppress 6506 
                bounds.Union(stroke.GetBounds());
#pragma warning restore 1634, 1691
            }
            return bounds; 
        }
 
        // ISSUE-2004/12/13-XIAOTU: In M8.2, the following two tap-hit APIs return the top-hit stroke, 
        // giving preference to non-highlighter strokes. We have decided not to treat highlighter and
        // non-highlighter differently and only return the top-hit stroke. But there are two remaining 
        // open-issues on this:
        //  1. Do we need to make these two APIs virtual, so user can treat highlighter differently if they
        //     want to?
        //  2. Since we are only returning the top-hit stroke, should we use Stroke as the return type? 
        //
 
        ///  
        /// Tap-hit. Hit tests all strokes within a point, and returns a StrokeCollection for these strokes.Internally does Stroke.HitTest(Point, 1pxlRectShape).
        ///  
        /// A StrokeCollection that either empty or contains the top hit stroke
        public StrokeCollection HitTest(Point point)
        {
            return PointHitTest(point, new RectangleStylusShape(1f, 1f)); 
        }
 
        ///  
        /// Tap-hit
        ///  
        /// The central point
        /// The diameter value of the circle
        /// A StrokeCollection that either empty or contains the top hit stroke
        public StrokeCollection HitTest(Point point, double diameter) 
        {
            if (Double.IsNaN(diameter) || diameter < DrawingAttributes.MinWidth || diameter > DrawingAttributes.MaxWidth) 
            { 
                throw new ArgumentOutOfRangeException("diameter", SR.Get(SRID.InvalidDiameter));
            } 
            return PointHitTest(point, new EllipseStylusShape(diameter, diameter));
        }

        ///  
        /// Hit-testing with lasso
        ///  
        /// points making the lasso 
        /// the margin value to tell whether a stroke
        /// is in or outside of the rect 
        /// collection of strokes found inside the rectangle
        public StrokeCollection HitTest(IEnumerable lassoPoints, int percentageWithinLasso)
        {
            // Check the input parameters 
            if (lassoPoints == null)
            { 
                throw new System.ArgumentNullException("lassoPoints"); 
            }
            if ((percentageWithinLasso < 0) || (percentageWithinLasso > 100)) 
            {
                throw new System.ArgumentOutOfRangeException("percentageWithinLasso");
            }
 
            if (IEnumerablePointHelper.GetCount(lassoPoints) < 3)
            { 
                return new StrokeCollection(); 
            }
 
            Lasso lasso = new SingleLoopLasso();
            lasso.AddPoints(lassoPoints);

            // Enumerate through the strokes and collect those captured by the lasso. 
            StrokeCollection lassoedStrokes = new StrokeCollection();
            foreach (Stroke stroke in this) 
            { 

                if (percentageWithinLasso == 0) 
                {
                    lassoedStrokes.Add(stroke);
                }
                else 
                {
                    StrokeInfo strokeInfo = null; 
                    try 
                    {
                        strokeInfo = new StrokeInfo(stroke); 

                        StylusPointCollection stylusPoints = strokeInfo.StylusPoints;
                        double target = strokeInfo.TotalWeight * percentageWithinLasso / 100.0f - Stroke.PercentageTolerance;
 
                        for (int i = 0; i < stylusPoints.Count; i++)
                        { 
                            if (true == lasso.Contains((Point)stylusPoints[i])) 
                            {
                                target -= strokeInfo.GetPointWeight(i); 
                                if (DoubleUtil.LessThanOrClose(target, 0f))
                                {
                                    lassoedStrokes.Add(stroke);
                                    break; 
                                }
                            } 
                        } 
                    }
                    finally 
                    {
                        if (strokeInfo != null)
                        {
                            //detach from event handlers, or else we leak. 
                            strokeInfo.Detach();
                        } 
                    } 
                }
            } 

            // Return the resulting collection
            return lassoedStrokes;
        } 

 
        ///  
        /// Hit-testing with rectangle
        ///  
        /// hitting rectangle
        /// the percentage of the stroke that must be within
        /// the bounds to be considered hit
        /// collection of strokes found inside the rectangle 
        public StrokeCollection HitTest(Rect bounds, int percentageWithinBounds)
        { 
            // Check the input parameters 
            if ((percentageWithinBounds < 0) || (percentageWithinBounds > 100))
            { 
                throw new System.ArgumentOutOfRangeException("percentageWithinBounds");
            }
            if (bounds.IsEmpty)
            { 
                return new StrokeCollection();
            } 
 
            // Enumerate thru the strokes collect those found within the rectangle.
            StrokeCollection hits = new StrokeCollection(); 
            foreach (Stroke stroke in this)
            {
                // samgeo - Presharp issue
                // Presharp gives a warning when get methods might deref a null.  It's complaining 
                // here that 'stroke'' could be null, but StrokeCollection never allows nulls to be added
                // so this is not possible 
#pragma warning disable 1634, 1691 
#pragma warning suppress 6506
                if (true == stroke.HitTest(bounds, percentageWithinBounds)) 
                {
                    hits.Add(stroke);
                }
#pragma warning restore 1634, 1691 
            }
            return hits; 
        } 

 
        /// 
        /// Issue: what's the return value
        /// 
        ///  
        /// 
        ///  
        public StrokeCollection HitTest(IEnumerable path, StylusShape stylusShape) 
        {
            // Check the input parameters 
            if (stylusShape == null)
            {
                throw new System.ArgumentNullException("stylusShape");
            } 
            if (path == null)
            { 
                throw new System.ArgumentNullException("path"); 
            }
            if (IEnumerablePointHelper.GetCount(path) == 0) 
            {
                return new StrokeCollection();
            }
 
            // validate input
            ErasingStroke erasingStroke = new ErasingStroke(stylusShape, path); 
            Rect erasingBounds = erasingStroke.Bounds; 
            if (erasingBounds.IsEmpty)
            { 
                return new StrokeCollection();
            }
            StrokeCollection hits = new StrokeCollection();
            foreach (Stroke stroke in this) 
            {
                // samgeo - Presharp issue 
                // Presharp gives a warning when get methods might deref a null.  It's complaining 
                // here that 'stroke'' could be null, but StrokeCollection never allows nulls to be added
                // so this is not possible 
#pragma warning disable 1634, 1691
#pragma warning suppress 6506
                if (erasingBounds.IntersectsWith(stroke.GetBounds()) &&
                    erasingStroke.HitTest(StrokeNodeIterator.GetIterator(stroke, stroke.DrawingAttributes))) 
                {
                    hits.Add(stroke); 
                } 
#pragma warning restore 1634, 1691
            } 

            return hits;
        }
 
        /// 
        /// Clips out all ink outside a given lasso 
        ///  
        /// lasso
        public void Clip(IEnumerable lassoPoints) 
        {
            // Check the input parameters
            if (lassoPoints == null)
            { 
                throw new System.ArgumentNullException("lassoPoints");
            } 
 
            int length = IEnumerablePointHelper.GetCount(lassoPoints);
            if (length == 0) 
            {
                throw new ArgumentException(SR.Get(SRID.EmptyArray));
            }
 
            if (length < 3)
            { 
                // 
                // if you're clipping with a point or a line with
                // two points, it doesn't matter where the line is or if it 
                // intersects any of the strokes, the point or line has no region
                // so technically everything in the strokecollection
                // should be removed
                // 
                this.Clear(); //raises the appropriate events
                return; 
            } 

            Lasso lasso = new SingleLoopLasso(); 
            lasso.AddPoints(lassoPoints);

            for (int i = 0; i < this.Count; i++)
            { 
                Stroke stroke = this[i];
                StrokeCollection clipResult = stroke.Clip(stroke.HitTest(lasso)); 
                UpdateStrokeCollection(stroke, clipResult, ref i); 
            }
        } 

        /// 
        /// Clips out all ink outside a given rectangle.
        ///  
        /// rectangle to clip with
        public void Clip(Rect bounds) 
        { 
            if (bounds.IsEmpty == false)
            { 
                Clip(new Point[4] { bounds.TopLeft, bounds.TopRight, bounds.BottomRight, bounds.BottomLeft });
            }
        }
 
        /// 
        /// Erases all ink inside a lasso 
        ///  
        /// lasso to erase within
        public void Erase(IEnumerable lassoPoints) 
        {
            // Check the input parameters
            if (lassoPoints == null)
            { 
                throw new System.ArgumentNullException("lassoPoints");
            } 
            int length = IEnumerablePointHelper.GetCount(lassoPoints); 
            if (length == 0)
            { 
                throw new ArgumentException(SR.Get(SRID.EmptyArray));
            }

            if (length < 3) 
            {
                return; 
            } 

            Lasso lasso = new SingleLoopLasso(); 
            lasso.AddPoints(lassoPoints);
            for (int i = 0; i < this.Count; i++)
            {
                Stroke stroke = this[i]; 

                StrokeCollection eraseResult = stroke.Erase(stroke.HitTest(lasso)); 
                UpdateStrokeCollection(stroke, eraseResult, ref i); 
            }
        } 


        /// 
        /// Erases all ink inside a given rectangle 
        /// 
        /// rectangle to erase within 
        public void Erase(Rect bounds) 
        {
            if (bounds.IsEmpty == false) 
            {
                Erase(new Point[4] { bounds.TopLeft, bounds.TopRight, bounds.BottomRight, bounds.BottomLeft });
            }
        } 

 
        ///  
        /// Erases all ink hit by the contour of an erasing stroke
        ///  
        /// Shape of the eraser
        /// a path making the spine of the erasing stroke 
        public void Erase(IEnumerable eraserPath, StylusShape eraserShape)
        { 
            // Check the input parameters
            if (eraserShape == null) 
            { 
                throw new System.ArgumentNullException(SR.Get(SRID.SCEraseShape));
            } 
            if (eraserPath == null)
            {
                throw new System.ArgumentNullException(SR.Get(SRID.SCErasePath));
            } 
            if (IEnumerablePointHelper.GetCount(eraserPath) == 0)
            { 
                return; 
            }
 
            ErasingStroke erasingStroke = new ErasingStroke(eraserShape, eraserPath);
            for (int i = 0; i < this.Count; i++)
            {
                Stroke stroke = this[i]; 

                List intersections = new List(); 
                erasingStroke.EraseTest(StrokeNodeIterator.GetIterator(stroke, stroke.DrawingAttributes), intersections); 
                StrokeCollection eraseResult = stroke.Erase(intersections.ToArray());
 
                UpdateStrokeCollection(stroke, eraseResult, ref i);
            }
        }
 
        /// 
        /// Render the StrokeCollection under the specified DrawingContext. 
        ///  
        /// 
        public void Draw(DrawingContext context) 
        {
             if (null == context)
            {
                throw new System.ArgumentNullException("context"); 
            }
 
            //The verification of UI context affinity is done in Stroke.Draw() 

            List solidStrokes = new List(); 
            Dictionary> highLighters = new Dictionary>();

            for (int i = 0; i < this.Count; i++)
            { 
                Stroke stroke = this[i];
                List strokes; 
                if (stroke.DrawingAttributes.IsHighlighter) 
                {
                    // It's very important to override the Alpha value so that Colors of the same RGB vale 
                    // but different Alpha would be in the same list.
                    Color color = StrokeRenderer.GetHighlighterColor(stroke.DrawingAttributes.Color);
                    if (highLighters.TryGetValue(color, out strokes) == false)
                    { 
                        strokes = new List();
                        highLighters.Add(color, strokes); 
                    } 
                    strokes.Add(stroke);
                } 
                else
                {
                    solidStrokes.Add(stroke);
                } 
            }
 
            foreach (List strokes in highLighters.Values) 
            {
                context.PushOpacity(StrokeRenderer.HighlighterOpacity); 
                try
                {
                    foreach (Stroke stroke in strokes)
                    { 
                        stroke.DrawInternal(context, StrokeRenderer.GetHighlighterAttributes(stroke, stroke.DrawingAttributes),
                                            false /*Don't draw selected stroke as hollow*/); 
                    } 
                }
                finally 
                {
                    context.Pop();
                }
            } 

            foreach(Stroke stroke in solidStrokes) 
            { 
                stroke.DrawInternal(context, stroke.DrawingAttributes, false/*Don't draw selected stroke as hollow*/);
            } 
        }
        #endregion

        #region Incremental hit-testing 

        ///  
        /// Creates an incremental hit-tester for hit-testing with a shape. 
        /// Scenarios: stroke-erasing and point-erasing
        ///  
        /// shape of the eraser
        /// an instance of IncrementalStrokeHitTester
        public IncrementalStrokeHitTester GetIncrementalStrokeHitTester(StylusShape eraserShape)
        { 
            if (eraserShape == null)
            { 
                throw new System.ArgumentNullException("eraserShape"); 
            }
            return new IncrementalStrokeHitTester(this, eraserShape); 
        }


        ///  
        /// Creates an incremental hit-tester for selecting with lasso.
        ///  
        /// The percentage of the stroke that must be within the lasso to be considered hit 
        /// an instance of incremental hit-tester
        public IncrementalLassoHitTester GetIncrementalLassoHitTester(int percentageWithinLasso) 
        {
            if ((percentageWithinLasso < 0) || (percentageWithinLasso > 100))
            {
                throw new System.ArgumentOutOfRangeException("percentageWithinLasso"); 
            }
            return new IncrementalLassoHitTester(this, percentageWithinLasso); 
        } 
        #endregion
 
        /// 
        /// Return all hit strokes that the StylusShape intersects and returns them in a StrokeCollection
        /// 
        private StrokeCollection PointHitTest(Point point, StylusShape shape) 
        {
            // Create the collection to return 
            StrokeCollection hits = new StrokeCollection(); 
            for (int i = 0; i < this.Count; i++)
            { 
                Stroke stroke = this[i];
                if (stroke.HitTest(new Point[] { point }, shape))
                {
                    hits.Add(stroke); 
                }
            } 
 
            return hits;
        } 

        private void UpdateStrokeCollection(Stroke original, StrokeCollection toReplace, ref int index)
        {
            System.Diagnostics.Debug.Assert(original != null && toReplace != null); 
            System.Diagnostics.Debug.Assert(index >= 0 && index < this.Count);
            if (toReplace.Count == 0) 
            { 
                Remove(original);
                index--; 
            }
            else if (!(toReplace.Count == 1 && toReplace[0] == original))
            {
                Replace(original, toReplace); 

                // Update the current index 
                index += toReplace.Count - 1; 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK