/*
* @author Valentin Simonov / http://va.lent.in/
*/
using System;
using System.Text;
using TouchScript.Core;
using TouchScript.Hit;
using TouchScript.InputSources;
using TouchScript.Layers;
using TouchScript.Utils;
using UnityEngine;
namespace TouchScript.Pointers
{
///
/// Representation of a pointer (touch, mouse) within TouchScript.
/// An instance of this class is created when user touches the screen. A unique id is assigned to it which doesn't change throughout its life.
/// Attention! Do not store references to these objects beyond pointer's lifetime (i.e. when target finger is lifted off). These objects may be reused internally. Store unique ids instead.
///
public class Pointer : IPointer, IEquatable
{
#region Constants
///
/// Invalid pointer id.
///
public const int INVALID_POINTER = -1;
///
/// This pointer is generated by script and is not mapped to any device input.
///
public const uint FLAG_ARTIFICIAL = 1 << 0;
///
/// This pointer was returned to the system after it was cancelled.
///
public const uint FLAG_RETURNED = 1 << 1;
///
/// This pointer is internal and shouldn't be shown on screen.
///
public const uint FLAG_INTERNAL = 1 << 2;
///
/// Pointer type.
///
public enum PointerType
{
///
/// Unknown.
///
Unknown,
///
/// Touch.
///
Touch,
///
/// Mouse.
///
Mouse,
///
/// Pen.
///
Pen,
///
/// Object.
///
Object
}
///
/// The state of buttons for a pointer. Combines 3 types of button events: Pressed (holding a button), Down (just pressed this frame) and Up (released this frame).
///
[Flags]
public enum PointerButtonState
{
///
/// No button is pressed.
///
Nothing = 0,
///
/// Indicates a primary action, analogous to a left mouse button down.
/// A or has this flag set when it is in contact with the digitizer surface.
/// A has this flag set when it is in contact with the digitizer surface with no buttons pressed.
/// A has this flag set when the left mouse button is down.
///
FirstButtonPressed = 1 << 0,
///
/// Indicates a secondary action, analogous to a right mouse button down.
/// A or does not use this flag.
/// A has this flag set when it is in contact with the digitizer surface with the pen barrel button pressed.
/// A has this flag set when the right mouse button is down.
///
SecondButtonPressed = 1 << 1,
///
/// Analogous to a mouse wheel button down.
/// A , or does not use this flag.
/// A has this flag set when the mouse wheel button is down.
///
ThirdButtonPressed = 1 << 2,
///
/// Analogous to the first extended button button down.
/// A , or does not use this flag.
/// A has this flag set when the first extended button is down.
///
FourthButtonPressed = 1 << 3,
///
/// Analogous to the second extended button button down.
/// A , or does not use this flag.
/// A has this flag set when the second extended button is down.
///
FifthButtonPressed = 1 << 4,
///
/// First button pressed this frame.
///
FirstButtonDown = 1 << 11,
///
/// First button released this frame.
///
FirstButtonUp = 1 << 12,
///
/// Second button pressed this frame.
///
SecondButtonDown = 1 << 13,
///
/// Second button released this frame.
///
SecondButtonUp = 1 << 14,
///
/// Third button pressed this frame.
///
ThirdButtonDown = 1 << 15,
///
/// Third button released this frame.
///
ThirdButtonUp = 1 << 16,
///
/// Fourth button pressed this frame.
///
FourthButtonDown = 1 << 17,
///
/// Fourth button released this frame.
///
FourthButtonUp = 1 << 18,
///
/// Fifth button pressed this frame.
///
FifthButtonDown = 1 << 19,
///
/// Fifth button released this frame.
///
FifthButtonUp = 1 << 20,
///
/// Any button is pressed.
///
AnyButtonPressed = FirstButtonPressed | SecondButtonPressed | ThirdButtonPressed | FourthButtonPressed | FifthButtonPressed,
///
/// Any button down this frame.
///
AnyButtonDown = FirstButtonDown | SecondButtonDown | ThirdButtonDown | FourthButtonDown | FifthButtonDown,
///
/// Any button up this frame.
///
AnyButtonUp = FirstButtonUp | SecondButtonUp | ThirdButtonUp | FourthButtonUp | FifthButtonUp
}
#endregion
#region Public properties
///
public int Id { get; private set; }
///
public PointerType Type { get; protected set; }
///
public PointerButtonState Buttons { get; set; }
///
public IInputSource InputSource { get; private set; }
///
public Vector2 Position
{
get { return position; }
set { newPosition = value; }
}
///
public Vector2 PreviousPosition { get; private set; }
///
public uint Flags { get; set; }
///
/// Projection parameters for the layer which created this pointer.
///
public ProjectionParams ProjectionParams
{
get
{
if (pressData.Layer == null) return null;
return pressData.Layer.GetProjectionParams(this);
}
}
#endregion
#region Private variables
private static StringBuilder builder;
private LayerManagerInstance layerManager;
private int refCount = 0;
private Vector2 position, newPosition;
private HitData pressData, overData;
private bool overDataIsDirty = true;
#endregion
#region Public methods
///
public HitData GetOverData(bool forceRecalculate = false)
{
if (overDataIsDirty || forceRecalculate)
{
layerManager.GetHitTarget(this, out overData);
overDataIsDirty = false;
}
return overData;
}
///
/// Returns when the pointer was pressed. If the pointer is not pressed uninitialized is returned.
///
public HitData GetPressData()
{
return pressData;
}
///
/// Copies values from the target.
///
/// The target pointer to copy values from.
public virtual void CopyFrom(Pointer target)
{
Type = target.Type;
Flags = target.Flags;
Buttons = target.Buttons;
position = target.position;
newPosition = target.newPosition;
PreviousPosition = target.PreviousPosition;
}
///
public override bool Equals(object other)
{
return Equals(other as Pointer);
}
///
public bool Equals(Pointer other)
{
if (other == null)
return false;
return Id == other.Id;
}
///
public override int GetHashCode()
{
return Id;
}
///
public override string ToString()
{
if (builder == null) builder = new StringBuilder();
builder.Length = 0;
builder.Append("(Pointer type: ");
builder.Append(Type);
builder.Append(", id: ");
builder.Append(Id);
builder.Append(", buttons: ");
PointerUtils.PressedButtonsToString(Buttons, builder);
builder.Append(", flags: ");
BinaryUtils.ToBinaryString(Flags, builder, 8);
builder.Append(", position: ");
builder.Append(Position);
builder.Append(")");
return builder.ToString();
}
#endregion
#region Constructor
///
/// Initializes a new instance of the class.
///
public Pointer(IInputSource input)
{
layerManager = LayerManager.Instance as LayerManagerInstance;
Type = PointerType.Unknown;
InputSource = input;
INTERNAL_Reset();
}
#endregion
#region Internal methods
internal virtual void INTERNAL_Init(int id)
{
Id = id;
PreviousPosition = position = newPosition;
}
internal virtual void INTERNAL_Reset()
{
Id = INVALID_POINTER;
INTERNAL_ClearPressData();
position = newPosition = PreviousPosition = Vector2.zero;
Flags = 0;
Buttons = PointerButtonState.Nothing;
overDataIsDirty = true;
}
internal virtual void INTERNAL_FrameStarted()
{
Buttons &= ~(PointerButtonState.AnyButtonDown | PointerButtonState.AnyButtonUp);
overDataIsDirty = true;
}
internal virtual void INTERNAL_UpdatePosition()
{
PreviousPosition = position;
position = newPosition;
}
internal void INTERNAL_Retain()
{
refCount++;
}
internal int INTERNAL_Release()
{
return --refCount;
}
internal void INTERNAL_SetPressData(HitData data)
{
pressData = data;
overData = data;
overDataIsDirty = false;
}
internal void INTERNAL_ClearPressData()
{
pressData = default(HitData);
refCount = 0;
}
#endregion
}
}