using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using TouchlibWrapper;
using NUIGroup.MultitouchFramework.Controls;
using System.Diagnostics;
//done for now
namespace NUIGroup
{
namespace MultitouchFramework
{
namespace Engines
{
///
/// Handles all touches, and registers all events
///
/// Note: This class is a singleton and provides registering/deregistering
/// of classes from anywhere and delegates all touch events to relevant
/// classes
///
public sealed class TouchEngine
{
#region Private Members
RoutedEvent[] _events = null;
TouchData data;
TouchEventArgs args;
static TouchEngine _instance = null;
static readonly object _padlock = new object();
//the base window that'll be used for hit testing
private UIElement _trackBase;
//linked list holding the registered classes
private LinkedList _classList = new LinkedList();
//to map the touchdata received from touchlib to actual screen coordinates
private double _screenHeight;
private double _screenWidth;
#endregion
#region Public Members
//delegates for events
public delegate void fingerDownHandler(object sender, TouchEventArgs e);
public delegate void fingerUpdateHandler(object sender, TouchEventArgs e);
public delegate void fingerUpHandler(object sender, TouchEventArgs e);
#endregion
#region Constructor
///
/// Private Constructor, singleton to enable registering of classes from
/// anywhere
///
private TouchEngine()
{
_screenHeight = SystemParameters.PrimaryScreenHeight;
_screenWidth = SystemParameters.PrimaryScreenWidth;
CsTI cs = CsTI.Instance();
cs.fingerDown += new TouchlibWrapper.fingerDownHandler(cs_fingerDown);
cs.fingerUpdate += new TouchlibWrapper.fingerUpdateHandler(cs_fingerUpdate);
cs.fingerUp += new TouchlibWrapper.fingerUpHandler(cs_fingerUp);
}
#endregion
#region Singleton
///
/// Returns instance of TouchEngine as it is a singleton class
///
public static TouchEngine Instance
{
get
{
lock (_padlock)
{
if (_instance == null)
{
_instance = new TouchEngine();
}
return _instance;
}
}
}
#endregion
#region Event Handlers
///
/// Handlers when a finger is pressed from touchlib
///
/// ID of finger
/// tagID of fiducial
/// x coordinate of finger
/// y coordinate of finger
/// TODO: get description
/// area of finger
/// height of fiducial
/// width of fiducial
/// deltaX used for finger movement
/// deltaY used for finger movement
void cs_fingerDown(int ID, int tagID, float X, float Y, float angle, float area, float height, float width, float dX, float dY)
{
/*
* finds the element that was touched and sends
* the event to the correct element
*/
UIElement elem = getTouchedElement(X * _screenWidth, Y * _screenHeight);
if (elem != null)
{
data = new TouchData(elem, ID, tagID, (float)(X * _screenWidth), (float)(Y * _screenHeight), angle, area, height, width, (float)(dX * _screenWidth), (float)(dY * _screenHeight));
args = new TouchEventArgs(data);
foreach (Type type in _classList)
{
if (elem.GetType() == type)
{
_events = EventManager.GetRoutedEventsForOwner(type);
for (int i = 0; i < _events.Length; i++)
{
if (_events[i].Name == "fingerDown")
{
args.RoutedEvent = _events[i];
try
{
elem.RaiseEvent(args);
}
catch(Exception ex)
{
//if an event was missed
Debug.WriteLine(ex.StackTrace);
}
}
}
}
}
}
}
///
/// Handlers when a finger is lifted from touchlib
///
/// ID of finger
/// tagID of fiducial
/// x coordinate of finger
/// y coordinate of finger
/// TODO: get description
/// area of finger
/// height of fiducial
/// width of fiducial
/// deltaX used for finger movement
/// deltaY used for finger movement
void cs_fingerUp(int ID, int tagID, float X, float Y, float angle, float area, float height, float width, float dX, float dY)
{
/*
* finds the element that was touched and sends
* the event to the correct element
*/
UIElement elem = getTouchedElement(X * _screenWidth, Y * _screenHeight);
if (elem != null)
{
data = new TouchData(elem, ID, tagID, (float)(X * _screenWidth), (float)(Y * _screenHeight), angle, area, height, width, (float)(dX * _screenWidth), (float)(dY * _screenHeight));
args = new TouchEventArgs(data);
foreach (Type type in _classList)
{
if (elem.GetType() == type)
{
_events = EventManager.GetRoutedEventsForOwner(type);
for (int i = 0; i < _events.Length; i++)
{
if (_events[i].Name == "fingerUp")
{
args.RoutedEvent = _events[i];
try
{
elem.RaiseEvent(args);
}
catch(Exception ex)
{
//if an event was missed
Debug.WriteLine(ex.StackTrace);
}
}
}
}
}
}
}
///
/// Handlers when a finger is moved from touchlib
///
/// ID of finger
/// tagID of fiducial
/// x coordinate of finger
/// y coordinate of finger
/// TODO: get description
/// area of finger
/// height of fiducial
/// width of fiducial
/// deltaX used for finger movement
/// deltaY used for finger movement
void cs_fingerUpdate(int ID, int tagID, float X, float Y, float angle, float area, float height, float width, float dX, float dY)
{
/*
* finds the element that was touched and sends
* the event to the correct element
*/
UIElement elem = getTouchedElement(X * _screenWidth, Y * _screenHeight);
if (elem != null)
{
data = new TouchData(elem, ID, tagID, (float)(X * _screenWidth), (float)(Y * _screenHeight), angle, area, height, width, (float)(dX * _screenWidth), (float)(dY * _screenHeight));
args = new TouchEventArgs(data);
foreach (Type type in _classList)
{
if (elem.GetType() == type)
{
_events = EventManager.GetRoutedEventsForOwner(type);
for (int i = 0; i < _events.Length; i++)
{
if (_events[i].Name == "fingerUpdate")
{
args.RoutedEvent = _events[i];
try
{
elem.RaiseEvent(args);
}
catch(Exception ex)
{
//if an event was missed
Debug.WriteLine(ex.StackTrace);
}
}
}
}
}
}
}
#endregion
#region Register/Deregister
///
/// Registers the class for receiving touch events
///
/// The class type to be registered
public void registerClass(Type type)
{
if (!_classList.Contains(type))
{
_classList.AddLast(type);
}
}
///
/// Deregisters the class for receiving touch events
///
/// The class type to be deregistered
public void deregisterClass(Type type)
{
if (_classList.Contains(type))
{
_classList.Remove(type);
}
}
#endregion
#region Start Tracking
///
/// Starts Touchlib. Must be called AFTER content (in window) has been
/// rendered
///
/// The element that'll be the base for hit testing
public void startTracking(UIElement trackBase)
{
Debug.WriteLine("CLASSES REGISTERED : " + _classList.Count);
_trackBase = trackBase;
CsTI cs = CsTI.Instance();
try
{
cs.startScreen();
}
//Throws a accessviolationexception for some reason
//from the CsTI module, I'll fix it soon
catch (AccessViolationException ex)
{
Console.WriteLine(ex.Message);
}
}
#endregion
#region Helper Methods
///
/// HitTest the application and find the Element that was touched
///
/// X coordinate of the touch
/// Y coordinate of the touch
/// The UIElement touched, null if no element found
UIElement getTouchedElement(double x, double y)
{
UIElement temp = null;
Point pt = new Point(Math.Floor(x), Math.Floor(y));
HitTestResult result = VisualTreeHelper.HitTest(_trackBase, pt);
if (result != null)
{
DependencyObject obj = (DependencyObject)result.VisualHit;
temp = findTouchedUIElement((UIElement)obj);
//Debug.WriteLine("TOUCHED ELEMENT: " + temp.GetType().ToString());
}
return temp;
}
///
/// Recursively finds the first touch control by walking up the visual
/// tree from the top element touched which in most cases won't be a touch control
///
/// The original element touched
/// The actual touch control
private UIElement findTouchedUIElement(UIElement el)
{
if ((UIElement)VisualTreeHelper.GetParent(el) != null)
{
if ((el.GetType().ToString().Contains("Touch")))
{
return el;
}
else return findTouchedUIElement((UIElement)VisualTreeHelper.GetParent(el));
}
return null;
}
#endregion
}
}
}
}