/* * @author Valentin Simonov / http://va.lent.in/ */ using System; using System.Collections.Generic; using TouchScript.Hit; using TouchScript.Layers; using TouchScript.Pointers; using UnityEngine; namespace TouchScript.Core { /// /// Internal implementation of . /// internal sealed class LayerManagerInstance : MonoBehaviour, ILayerManager { #region Public properties /// /// Gets the instance of GestureManager singleton. /// public static ILayerManager Instance { get { if (shuttingDown) return null; if (instance == null) { if (!Application.isPlaying) return null; var objects = FindObjectsOfType(); if (objects.Length == 0) { var go = new GameObject("GestureManager Instance"); instance = go.AddComponent(); } else if (objects.Length >= 1) { instance = objects[0]; } } return instance; } } /// public IList Layers { get { return new List(layers); } } /// public int LayerCount { get { return layerCount; } } /// public bool HasExclusive { get { return exclusiveCount > 0; } } #endregion #region Private variables private static LayerManagerInstance instance; private static bool shuttingDown = false; private ITouchManager manager; private List layers = new List(10); private int layerCount = 0; private HashSet exclusive = new HashSet(); private int exclusiveCount = 0; private int clearExclusiveDelay = -1; #endregion #region Temporary variables // Used in SetExclusive(). private List tmpList = new List(20); #endregion #region Public methods /// public bool AddLayer(TouchLayer layer, int index = -1, bool addIfExists = true) { if (layer == null) return false; var i = layers.IndexOf(layer); if (i != -1) { if (!addIfExists) return false; layers.RemoveAt(i); layerCount--; } if (index == 0) { layers.Insert(0, layer); layerCount++; return i == -1; } if (index == -1 || index >= layerCount) { layers.Add(layer); layerCount++; return i == -1; } if (i != -1) { if (index < i) layers.Insert(index, layer); else layers.Insert(index - 1, layer); layerCount++; return false; } layers.Insert(index, layer); layerCount++; return true; } /// public bool RemoveLayer(TouchLayer layer) { if (layer == null) return false; var result = layers.Remove(layer); if (result) layerCount--; return result; } /// public void ChangeLayerIndex(int at, int to) { if (at < 0 || at >= layerCount) return; if (to < 0 || to >= layerCount) return; var data = layers[at]; layers.RemoveAt(at); layers.Insert(to, data); } /// public void ForEach(Func action) { for (var i = 0; i < layerCount; i++) { if (!action(layers[i])) break; } } /// public bool GetHitTarget(IPointer pointer, out HitData hit) { hit = default(HitData); for (var i = 0; i < layerCount; i++) { var touchLayer = layers[i]; if (touchLayer == null) continue; var result = touchLayer.Hit(pointer, out hit); switch (result) { case HitResult.Hit: return true; case HitResult.Discard: return false; } } return false; } /// public void SetExclusive(Transform target, bool includeChildren = false) { if (target == null) return; exclusive.Clear(); clearExclusiveDelay = -1; exclusive.Add(target.GetHashCode()); exclusiveCount = 1; if (includeChildren) { target.GetComponentsInChildren(tmpList); foreach (var t in tmpList) exclusive.Add(t.GetHashCode()); exclusiveCount += tmpList.Count; } } /// public void SetExclusive(IEnumerable targets) { if (targets == null) return; exclusive.Clear(); clearExclusiveDelay = -1; foreach (var t in targets) { exclusive.Add(t.GetHashCode()); exclusiveCount++; } } /// public bool IsExclusive(Transform target) { return exclusive.Contains(target.GetHashCode()); } /// public void ClearExclusive() { // It is incorrect to just set exclusiveCount to zero since the exclusive list is actually needed the next frame. Only after the next frame's FrameEnded event the list can be cleared. // If we are inside the Pointer Frame, we need to wait for the second FrameEnded (this frame's event included). Otherwise, we need to wait for the next FrameEnded event. clearExclusiveDelay = manager.IsInsidePointerFrame ? 2 : 1; } #endregion #region Unity private void Awake() { if (instance == null) { instance = this; } else if (instance != this) { Destroy(this); return; } manager = TouchManager.Instance; gameObject.hideFlags = HideFlags.HideInHierarchy; DontDestroyOnLoad(gameObject); } private void OnEnable() { manager.FrameFinished += frameFinishedHandler; } private void OnDisable() { manager.FrameFinished -= frameFinishedHandler; } private void OnApplicationQuit() { shuttingDown = true; } #endregion #region Private functions #endregion #region Event handlers private void frameFinishedHandler(object sender, EventArgs eventArgs) { clearExclusiveDelay--; if (clearExclusiveDelay == 0) { exclusive.Clear(); exclusiveCount = 0; } } #endregion } }