//-----------------------------------------------------------------------------
// 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;
}
}