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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XmlResolver.cs
- FieldNameLookup.cs
- DiagnosticsConfigurationHandler.cs
- MenuItem.cs
- DiagnosticTraceSource.cs
- SyntaxCheck.cs
- TranslateTransform.cs
- SectionVisual.cs
- ElementUtil.cs
- ConfigurationValue.cs
- CharConverter.cs
- ConfigViewGenerator.cs
- ZoneLinkButton.cs
- CustomErrorsSectionWrapper.cs
- ToolBarButtonClickEvent.cs
- ExtensionDataReader.cs
- CodeTypeOfExpression.cs
- ViewStateAttachedPropertyFeature.cs
- CollectionChangeEventArgs.cs
- EncoderParameter.cs
- PersonalizationProviderHelper.cs
- ArgumentNullException.cs
- XmlLanguage.cs
- AdCreatedEventArgs.cs
- FormViewModeEventArgs.cs
- AssociationTypeEmitter.cs
- XamlDesignerSerializationManager.cs
- GridViewUpdateEventArgs.cs
- StylusPointPropertyUnit.cs
- ParameterBuilder.cs
- InfoCardArgumentException.cs
- LiteralText.cs
- DbConnectionPoolGroupProviderInfo.cs
- RangeValueProviderWrapper.cs
- DebugView.cs
- LinkTarget.cs
- DataBoundControlAdapter.cs
- CodeCatchClauseCollection.cs
- ComplexBindingPropertiesAttribute.cs
- ErrorInfoXmlDocument.cs
- StylusTip.cs
- HelpInfo.cs
- ColorContext.cs
- PageSetupDialog.cs
- NumericUpDown.cs
- RoleManagerEventArgs.cs
- ClientConfigurationSystem.cs
- BooleanKeyFrameCollection.cs
- IsolatedStorageFileStream.cs
- StringFormat.cs
- XmlHierarchicalEnumerable.cs
- IssuanceLicense.cs
- LoadGrammarCompletedEventArgs.cs
- UpdateManifestForBrowserApplication.cs
- CodeTryCatchFinallyStatement.cs
- ActivityDesignerResources.cs
- LicFileLicenseProvider.cs
- RegexGroup.cs
- Win32.cs
- thaishape.cs
- WindowsAuthenticationModule.cs
- Visual3D.cs
- CollaborationHelperFunctions.cs
- ArrayListCollectionBase.cs
- IxmlLineInfo.cs
- SystemUnicastIPAddressInformation.cs
- DateTimePickerDesigner.cs
- SafeRegistryHandle.cs
- EntityUtil.cs
- odbcmetadatacollectionnames.cs
- ConnectorSelectionGlyph.cs
- UnsafeNativeMethods.cs
- DataControlFieldCell.cs
- __Filters.cs
- XmlUTF8TextWriter.cs
- BitmapDownload.cs
- DbConnectionInternal.cs
- AuthenticateEventArgs.cs
- ConditionalAttribute.cs
- __Filters.cs
- InstanceCreationEditor.cs
- CanonicalFontFamilyReference.cs
- TextDecorations.cs
- SqlRecordBuffer.cs
- Roles.cs
- SortedDictionary.cs
- CharacterHit.cs
- mda.cs
- DesignerSerializationVisibilityAttribute.cs
- OdbcEnvironmentHandle.cs
- ToolStripCollectionEditor.cs
- CodeTypeConstructor.cs
- LogoValidationException.cs
- GradientStop.cs
- TriggerAction.cs
- ArrayList.cs
- ProjectionCamera.cs
- PtsHelper.cs
- MultiView.cs
- ObjectResult.cs