//----------------------------------------------------------------------------- // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Linq; using System.Text; using Windows7.Multitouch.ManipulationInterop; using System.Runtime.InteropServices.ComTypes; using System.Drawing; using System.Runtime.InteropServices; namespace Windows7.Multitouch.Manipulation { /// /// A manipulation processor that support Inertia processing /// public class ManipulationInertiaProcessor : ManipulationProcessor { private InertiaProcessor _inertiaProcessor; /// /// Create new manipulation processor /// /// /// Call the , , to feed the processor. /// Register on , and /// to handle manipulation events /// Set the properties to get the desired inertia behavior /// Register to the event to set the inertia properties when inertia is starting/> /// /// Activate specific manipulation (scale, translate, rotate) /// The GUI timer that will be used for inertia events public ManipulationInertiaProcessor(ProcessorManipulations supportedManipulations, IGUITimer timer) : base(supportedManipulations) { _inertiaProcessor.SetTimer(timer); BeforeInertia += (s, e) => { }; } /// /// Fired just before inertia is starting /// public event EventHandler BeforeInertia; //Call by the base ctor internal override IManipulationEvents ManipulationEventHandler { get { if (_inertiaProcessor == null) _inertiaProcessor = new InertiaProcessor(this); return _inertiaProcessor; } } /// /// Release the underline COM object /// /// protected override void Dispose(bool dispose) { if (dispose) { _inertiaProcessor.Dispose(); base.Dispose(dispose); } } /// /// The inertia processor that is associate with the Manipulation Processor /// public InertiaProcessor InertiaProcessor { get { return _inertiaProcessor; } } internal IManipulationEvents ManipulationEvents { get { return this as IManipulationEvents; } } internal bool OnBeforeInertia() { BeforeInertiaEventArgs args = new BeforeInertiaEventArgs(); BeforeInertia(this, args); return args.CancelInertia; } } /// /// The Inertia Processor /// /// Handles calculations regarding object motion for multitouch public class InertiaProcessor : IManipulationEvents, IDisposable { private readonly IInertiaProcessor _comInertiaProcessor; private readonly ManipulationInertiaProcessor _manipulationProcessor; private readonly ManipulationEvents _comManipulationEvents; private int _inertiaCounter = 0; private bool _inInertia = false; private IGUITimer _timer; internal InertiaProcessor(ManipulationInertiaProcessor processor) { _comInertiaProcessor = new ManipulationInterop.InertiaProcessor(); _manipulationProcessor = processor; _comManipulationEvents = new ManipulationEvents(_comInertiaProcessor, processor as IManipulationEvents); MaxInertiaSteps = 200; InertiaTimerInterval = 15; } private void ResetInertia() { _inertiaCounter = 0; _timer.Stop(); _inInertia = false; } /// /// After this amount of timer ticks, the Inertia will stop /// public int MaxInertiaSteps { get; set; } /// /// The timer resolution for inertia events /// public int InertiaTimerInterval { get; set; } #region IManipulationEvents Members void IManipulationEvents.ManipulationStarted(float x, float y) { ResetInertia(); _manipulationProcessor.ManipulationEvents.ManipulationStarted(x, y); } void IManipulationEvents.ManipulationDelta(float x, float y, float translationDeltaX, float translationDeltaY, float scaleDelta, float expansionDelta, float rotationDelta, float cumulativeTranslationX, float cumulativeTranslationY, float cumulativeScale, float cumulativeExpansion, float cumulativeRotation) { _manipulationProcessor.ManipulationEvents.ManipulationDelta(x, y, translationDeltaX, translationDeltaY, scaleDelta, expansionDelta, rotationDelta, cumulativeTranslationX, cumulativeTranslationY, cumulativeScale, cumulativeExpansion, cumulativeRotation); } void IManipulationEvents.ManipulationCompleted(float x, float y, float cumulativeTranslationX, float cumulativeTranslationY, float cumulativeScale, float cumulativeExpansion, float cumulativeRotation) { if (_inInertia == true) { ResetInertia(); return; } //else if (_manipulationProcessor.OnBeforeInertia() == true) return; _inInertia = true; _timer.Interval = InertiaTimerInterval; _timer.Tick += (s, e) => { ++_inertiaCounter; if (_inertiaCounter > MaxInertiaSteps) { ResetInertia(); _comInertiaProcessor.Complete(); } else { _comInertiaProcessor.Process(); } }; _comInertiaProcessor.InitialOriginX = x; _comInertiaProcessor.InitialOriginY = y; _comInertiaProcessor.Reset(); _timer.Start(); } #endregion /// /// True when the inertia processor generate inertia motion events /// public bool InInertia { get { return _inInertia; } } /// /// Specifies the initial movement of the target object /// public VectorF InitialVelocity { get { return new VectorF(_comInertiaProcessor.InitialVelocityX, _comInertiaProcessor.InitialVelocityY); } set { _comInertiaProcessor.InitialVelocityX = value.X; _comInertiaProcessor.InitialVelocityY = value.Y; } } /// /// Specifies the rotation of the target when movement begins /// public float InitialAngularVelocity { get { return _comInertiaProcessor.InitialAngularVelocity; } set { _comInertiaProcessor.InitialAngularVelocity = value; } } /// /// Specifies the expention of the target when movement begins /// public float InitialExpansionVelocity { get { return _comInertiaProcessor.InitialExpansionVelocity; } set { _comInertiaProcessor.InitialExpansionVelocity = value; } } /// /// Specifies the distance from the edge of the target to its center before the object was changed /// public float InitialRadius { get { return _comInertiaProcessor.InitialRadius; } set { _comInertiaProcessor.InitialRadius = value; } } /// /// Limits how far towards the edge of the screen the target object can move /// public RectangleF Boundary { get { return new RectangleF( _comInertiaProcessor.BoundaryLeft, _comInertiaProcessor.BoundaryTop, _comInertiaProcessor.BoundaryRight - _comInertiaProcessor.BoundaryLeft, _comInertiaProcessor.BoundaryBottom - _comInertiaProcessor.BoundaryTop); } set { _comInertiaProcessor.BoundaryLeft = value.Left; _comInertiaProcessor.BoundaryRight = value.Right; _comInertiaProcessor.BoundaryTop = value.Top; _comInertiaProcessor.BoundaryBottom = value.Bottom; } } /// /// Specifies the rectangle region for bouncing the target objec /// public RectangleF ElasticMargin { get { return new RectangleF( _comInertiaProcessor.ElasticMarginLeft, _comInertiaProcessor.ElasticMarginTop, _comInertiaProcessor.ElasticMarginRight - _comInertiaProcessor.ElasticMarginLeft, _comInertiaProcessor.ElasticMarginBottom - _comInertiaProcessor.ElasticMarginTop); } set { _comInertiaProcessor.ElasticMarginLeft = value.Left; _comInertiaProcessor.ElasticMarginRight = value.Right; _comInertiaProcessor.ElasticMarginTop = value.Top; _comInertiaProcessor.ElasticMarginBottom = value.Bottom; } } /// /// Specifies the desired distance that the object will travel /// public float DesiredDisplacement { get { return _comInertiaProcessor.DesiredDisplacement; } set { _comInertiaProcessor.DesiredDisplacement = value; } } /// /// Specifies the desired radians that the object will rotate /// public float DesiredRotation { get { return _comInertiaProcessor.DesiredRotation; } set { _comInertiaProcessor.DesiredRotation = value; } } /// /// Specifies the desired change in the object's average radius /// public float DesiredExpansion { get { return _comInertiaProcessor.DesiredExpansion; } set { _comInertiaProcessor.DesiredExpansion = value; } } /// /// Specifies the desired rate at which translation operations will decelerate /// public float DesiredDeceleration { get { return _comInertiaProcessor.DesiredDeceleration; } set { _comInertiaProcessor.DesiredDeceleration = value; } } /// /// Specifies the desired rate that the target object will stop spinning in radians per msec /// public float DesiredAngularDeceleration { get { return _comInertiaProcessor.DesiredAngularDeceleration; } set { _comInertiaProcessor.DesiredAngularDeceleration = value; } } /// /// Specifies the rate at which the object will stop expanding /// public float DesiredExpansionDeceleration { get { return _comInertiaProcessor.DesiredExpansionDeceleration; } set { _comInertiaProcessor.DesiredExpansionDeceleration = value; } } #region IDisposable Members /// /// Dispose the object and release the underline COM object /// public void Dispose() { Marshal.ReleaseComObject(_comInertiaProcessor); _timer.Stop(); _timer.Dispose(); } #endregion internal void SetTimer(IGUITimer timer) { _timer = timer; } } /// /// Before Inertia phase is starting /// public class BeforeInertiaEventArgs : EventArgs { /// /// Cancel Inertia by setting this property to true /// public bool CancelInertia; } }