|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using SR = MS.Internal.PresentationCore.SR;
#pragma warning disable 1634, 1691 // suppressing PreSharp warnings
namespace System.Windows.Input
{
/// <summary>
/// StylusPointDescription describes the properties that a StylusPoint supports.
/// </summary>
public class StylusPointDescription
{
/// <summary>
/// Internal statics for our magic numbers
/// </summary>
internal const int RequiredCountOfProperties = 3;
internal const int RequiredXIndex = 0;
internal const int RequiredYIndex = 1;
internal const int RequiredPressureIndex = 2;
internal const int MaximumButtonCount = 31;
private int _buttonCount = 0;
private int _originalPressureIndex = RequiredPressureIndex;
private StylusPointPropertyInfo[] _stylusPointPropertyInfos;
/// <summary>
/// StylusPointDescription
/// </summary>
public StylusPointDescription()
{
//implement the default packet description
_stylusPointPropertyInfos =
new StylusPointPropertyInfo[]
{
StylusPointPropertyInfoDefaults.X,
StylusPointPropertyInfoDefaults.Y,
StylusPointPropertyInfoDefaults.NormalPressure
};
}
/// <summary>
/// StylusPointDescription
/// </summary>
public StylusPointDescription(IEnumerable<StylusPointPropertyInfo> stylusPointPropertyInfos)
{
ArgumentNullException.ThrowIfNull(stylusPointPropertyInfos);
List<StylusPointPropertyInfo> infos =
new List<StylusPointPropertyInfo>(stylusPointPropertyInfos);
if (infos.Count < RequiredCountOfProperties ||
infos[RequiredXIndex].Id != StylusPointPropertyIds.X ||
infos[RequiredYIndex].Id != StylusPointPropertyIds.Y ||
infos[RequiredPressureIndex].Id != StylusPointPropertyIds.NormalPressure)
{
throw new ArgumentException(SR.InvalidStylusPointDescription, "stylusPointPropertyInfos");
}
//
// look for duplicates, validate that buttons are last
//
List<Guid> seenIds = new List<Guid>();
seenIds.Add(StylusPointPropertyIds.X);
seenIds.Add(StylusPointPropertyIds.Y);
seenIds.Add(StylusPointPropertyIds.NormalPressure);
int buttonCount = 0;
for (int x = RequiredCountOfProperties; x < infos.Count; x++)
{
if (seenIds.Contains(infos[x].Id))
{
throw new ArgumentException(SR.InvalidStylusPointDescriptionDuplicatesFound, "stylusPointPropertyInfos");
}
if (infos[x].IsButton)
{
buttonCount++;
}
else
{
//this is not a button, make sure we haven't seen one before
if (buttonCount > 0)
{
throw new ArgumentException(SR.InvalidStylusPointDescriptionButtonsMustBeLast, "stylusPointPropertyInfos");
}
}
seenIds.Add(infos[x].Id);
}
if (buttonCount > MaximumButtonCount)
{
throw new ArgumentException(SR.InvalidStylusPointDescriptionTooManyButtons, "stylusPointPropertyInfos");
}
_buttonCount = buttonCount;
_stylusPointPropertyInfos = infos.ToArray();
}
/// <summary>
/// StylusPointDescription
/// </summary>
/// <param name="stylusPointPropertyInfos">stylusPointPropertyInfos</param>
/// <param name="originalPressureIndex">originalPressureIndex - does the digitizer really support pressure? If so, the index this was at</param>
internal StylusPointDescription(IEnumerable<StylusPointPropertyInfo> stylusPointPropertyInfos, int originalPressureIndex)
: this (stylusPointPropertyInfos)
{
_originalPressureIndex = originalPressureIndex;
}
/// <summary>
/// HasProperty
/// </summary>
/// <param name="stylusPointProperty">stylusPointProperty</param>
public bool HasProperty(StylusPointProperty stylusPointProperty)
{
ArgumentNullException.ThrowIfNull(stylusPointProperty);
int index = IndexOf(stylusPointProperty.Id);
if (-1 == index)
{
return false;
}
return true;
}
/// <summary>
/// The count of properties this StylusPointDescription contains
/// </summary>
public int PropertyCount
{
get { return _stylusPointPropertyInfos.Length; }
}
/// <summary>
/// GetProperty
/// </summary>
/// <param name="stylusPointProperty">stylusPointProperty</param>
public StylusPointPropertyInfo GetPropertyInfo(StylusPointProperty stylusPointProperty)
{
ArgumentNullException.ThrowIfNull(stylusPointProperty);
return GetPropertyInfo(stylusPointProperty.Id);
}
/// <summary>
/// GetPropertyInfo
/// </summary>
/// <param name="guid">guid</param>
internal StylusPointPropertyInfo GetPropertyInfo(Guid guid)
{
int index = IndexOf(guid);
if (-1 == index)
{
//we didn't find it
throw new ArgumentException("stylusPointProperty");
}
return _stylusPointPropertyInfos[index];
}
/// <summary>
/// Returns the index of the given StylusPointProperty by ID, or -1 if none is found
/// </summary>
internal int GetPropertyIndex(Guid guid)
{
return IndexOf(guid);
}
/// <summary>
/// GetStylusPointProperties
/// </summary>
public ReadOnlyCollection<StylusPointPropertyInfo> GetStylusPointProperties()
{
return new ReadOnlyCollection<StylusPointPropertyInfo>(_stylusPointPropertyInfos);
}
/// <summary>
/// GetStylusPointPropertyIdss
/// </summary>
internal Guid[] GetStylusPointPropertyIds()
{
Guid[] ret = new Guid[_stylusPointPropertyInfos.Length];
for (int x = 0; x < ret.Length; x++)
{
ret[x] = _stylusPointPropertyInfos[x].Id;
}
return ret;
}
/// <summary>
/// Internal helper for determining how many ints in a raw int array
/// correspond to one point we get from the input system
/// </summary>
internal int GetInputArrayLengthPerPoint()
{
int buttonLength = _buttonCount > 0 ? 1 : 0;
int propertyLength = (_stylusPointPropertyInfos.Length - _buttonCount) + buttonLength;
if (!this.ContainsTruePressure)
{
propertyLength--;
}
return propertyLength;
}
/// <summary>
/// Internal helper for determining how many members a StylusPoint's
/// internal int[] should be for additional data
/// </summary>
internal int GetExpectedAdditionalDataCount()
{
int buttonLength = _buttonCount > 0 ? 1 : 0;
int expectedLength = ((_stylusPointPropertyInfos.Length - _buttonCount) + buttonLength) - 3 /*x, y, p*/;
return expectedLength;
}
/// <summary>
/// Internal helper for determining how many ints in a raw int array
/// correspond to one point when saving to himetric
/// </summary>
/// <returns></returns>
internal int GetOutputArrayLengthPerPoint()
{
int length = GetInputArrayLengthPerPoint();
if (!this.ContainsTruePressure)
{
length++;
}
return length;
}
/// <summary>
/// Internal helper for determining how many buttons are present
/// </summary>
internal int ButtonCount
{
get
{
return _buttonCount;
}
}
/// <summary>
/// Internal helper for determining what bit position the button is at
/// </summary>
internal int GetButtonBitPosition(StylusPointProperty buttonProperty)
{
if (!buttonProperty.IsButton)
{
throw new InvalidOperationException();
}
int buttonIndex = 0;
for (int x = _stylusPointPropertyInfos.Length - _buttonCount; //start of the buttons
x < _stylusPointPropertyInfos.Length; x++)
{
if (_stylusPointPropertyInfos[x].Id == buttonProperty.Id)
{
return buttonIndex;
}
if (_stylusPointPropertyInfos[x].IsButton)
{
// we're in the buttons, but this isn't the right one,
// bump the button index and keep looking
buttonIndex++;
}
}
return -1;
}
/// <summary>
/// ContainsTruePressure - true if this StylusPointDescription was instanced
/// by a TabletDevice or by ISF serialization that contains NormalPressure
/// </summary>
internal bool ContainsTruePressure
{
get { return (_originalPressureIndex != -1); }
}
/// <summary>
/// Internal helper to determine the original pressure index
/// </summary>
internal int OriginalPressureIndex
{
get { return _originalPressureIndex; }
}
/// <summary>
/// Returns true if the two StylusPointDescriptions have the same StylusPointProperties. Metrics are ignored.
/// </summary>
/// <param name="stylusPointDescription1">stylusPointDescription1</param>
/// <param name="stylusPointDescription2">stylusPointDescription2</param>
public static bool AreCompatible(StylusPointDescription stylusPointDescription1, StylusPointDescription stylusPointDescription2)
{
if (stylusPointDescription1 == null || stylusPointDescription2 == null)
{
throw new ArgumentNullException("stylusPointDescription");
}
#pragma warning disable 6506 // if a StylusPointDescription is not null, then _stylusPointPropertyInfos is not null.
//
// ignore X, Y, Pressure - they are guaranteed to be the first3 members
//
Debug.Assert( stylusPointDescription1._stylusPointPropertyInfos.Length >= RequiredCountOfProperties &&
stylusPointDescription1._stylusPointPropertyInfos[0].Id == StylusPointPropertyIds.X &&
stylusPointDescription1._stylusPointPropertyInfos[1].Id == StylusPointPropertyIds.Y &&
stylusPointDescription1._stylusPointPropertyInfos[2].Id == StylusPointPropertyIds.NormalPressure);
Debug.Assert( stylusPointDescription2._stylusPointPropertyInfos.Length >= RequiredCountOfProperties &&
stylusPointDescription2._stylusPointPropertyInfos[0].Id == StylusPointPropertyIds.X &&
stylusPointDescription2._stylusPointPropertyInfos[1].Id == StylusPointPropertyIds.Y &&
stylusPointDescription2._stylusPointPropertyInfos[2].Id == StylusPointPropertyIds.NormalPressure);
if (stylusPointDescription1._stylusPointPropertyInfos.Length != stylusPointDescription2._stylusPointPropertyInfos.Length)
{
return false;
}
for (int x = RequiredCountOfProperties; x < stylusPointDescription1._stylusPointPropertyInfos.Length; x++)
{
if (!StylusPointPropertyInfo.AreCompatible(stylusPointDescription1._stylusPointPropertyInfos[x], stylusPointDescription2._stylusPointPropertyInfos[x]))
{
return false;
}
}
#pragma warning restore 6506
return true;
}
/// <summary>
/// Returns a new StylusPointDescription with the common StylusPointProperties from both
/// </summary>
/// <param name="stylusPointDescription">stylusPointDescription</param>
/// <param name="stylusPointDescriptionPreserveInfo">stylusPointDescriptionPreserveInfo</param>
/// <remarks>The StylusPointProperties from stylusPointDescriptionPreserveInfo will be returned in the new StylusPointDescription</remarks>
public static StylusPointDescription GetCommonDescription(StylusPointDescription stylusPointDescription, StylusPointDescription stylusPointDescriptionPreserveInfo)
{
ArgumentNullException.ThrowIfNull(stylusPointDescription);
ArgumentNullException.ThrowIfNull(stylusPointDescriptionPreserveInfo);
#pragma warning disable 6506 // if a StylusPointDescription is not null, then _stylusPointPropertyInfos is not null.
//
// ignore X, Y, Pressure - they are guaranteed to be the first3 members
//
Debug.Assert(stylusPointDescription._stylusPointPropertyInfos.Length >= 3 &&
stylusPointDescription._stylusPointPropertyInfos[0].Id == StylusPointPropertyIds.X &&
stylusPointDescription._stylusPointPropertyInfos[1].Id == StylusPointPropertyIds.Y &&
stylusPointDescription._stylusPointPropertyInfos[2].Id == StylusPointPropertyIds.NormalPressure);
Debug.Assert(stylusPointDescriptionPreserveInfo._stylusPointPropertyInfos.Length >= 3 &&
stylusPointDescriptionPreserveInfo._stylusPointPropertyInfos[0].Id == StylusPointPropertyIds.X &&
stylusPointDescriptionPreserveInfo._stylusPointPropertyInfos[1].Id == StylusPointPropertyIds.Y &&
stylusPointDescriptionPreserveInfo._stylusPointPropertyInfos[2].Id == StylusPointPropertyIds.NormalPressure);
//add x, y, p
List<StylusPointPropertyInfo> commonProperties = new List<StylusPointPropertyInfo>();
commonProperties.Add(stylusPointDescriptionPreserveInfo._stylusPointPropertyInfos[0]);
commonProperties.Add(stylusPointDescriptionPreserveInfo._stylusPointPropertyInfos[1]);
commonProperties.Add(stylusPointDescriptionPreserveInfo._stylusPointPropertyInfos[2]);
//add common properties
for (int x = RequiredCountOfProperties; x < stylusPointDescription._stylusPointPropertyInfos.Length; x++)
{
for (int y = RequiredCountOfProperties; y < stylusPointDescriptionPreserveInfo._stylusPointPropertyInfos.Length; y++)
{
if (StylusPointPropertyInfo.AreCompatible( stylusPointDescription._stylusPointPropertyInfos[x],
stylusPointDescriptionPreserveInfo._stylusPointPropertyInfos[y]))
{
commonProperties.Add(stylusPointDescriptionPreserveInfo._stylusPointPropertyInfos[y]);
}
}
}
#pragma warning restore 6506
return new StylusPointDescription(commonProperties);
}
/// <summary>
/// Returns true if this StylusPointDescription is a subset
/// of the StylusPointDescription passed in
/// </summary>
/// <param name="stylusPointDescriptionSuperset">stylusPointDescriptionSuperset</param>
/// <returns></returns>
public bool IsSubsetOf(StylusPointDescription stylusPointDescriptionSuperset)
{
ArgumentNullException.ThrowIfNull(stylusPointDescriptionSuperset);
if (stylusPointDescriptionSuperset._stylusPointPropertyInfos.Length < _stylusPointPropertyInfos.Length)
{
return false;
}
//
// iterate through our local properties and make sure that the
// superset contains them
//
for (int x = 0; x < _stylusPointPropertyInfos.Length; x++)
{
Guid id = _stylusPointPropertyInfos[x].Id;
if (-1 == stylusPointDescriptionSuperset.IndexOf(id))
{
return false;
}
}
return true;
}
/// <summary>
/// Returns the index of the given StylusPointProperty, or -1 if none is found
/// </summary>
/// <param name="propertyId">propertyId</param>
private int IndexOf(Guid propertyId)
{
for (int x = 0; x < _stylusPointPropertyInfos.Length; x++)
{
if (_stylusPointPropertyInfos[x].Id == propertyId)
{
return x;
}
}
return -1;
}
}
}
|