BrowserCursor.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using System;
  2. using UnityEngine;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using CursorType = ZenFulcrum.EmbeddedBrowser.BrowserNative.CursorType;
  7. using Object = UnityEngine.Object;
  8. namespace ZenFulcrum.EmbeddedBrowser {
  9. /**
  10. * Manages finding and copying cursors for you.
  11. * Each instance has one active cursor and a Texture2D you can read from to use it.
  12. */
  13. public class BrowserCursor {
  14. public class CursorInfo {
  15. public int atlasOffset;
  16. public Vector2 hotspot;
  17. }
  18. private static Dictionary<CursorType, CursorInfo> mapping = new Dictionary<CursorType, CursorInfo>();
  19. private static bool loaded = false;
  20. private static int size;
  21. private static Texture2D allCursors;
  22. /// <summary>
  23. /// Fired when the mouse cursor's appearance or hotspot changes.
  24. /// Also fired when the mouse enters/leaves the browser.
  25. /// </summary>
  26. public event Action cursorChange = () => {};
  27. private static void Load() {
  28. if (loaded) return;
  29. allCursors = Resources.Load<Texture2D>("Browser/Cursors");
  30. if (!allCursors) throw new Exception("Failed to find browser allCursors");
  31. size = allCursors.height;
  32. var listObj = Resources.Load<TextAsset>("Browser/Cursors");
  33. foreach (var row in listObj.text.Split('\n')) {
  34. var info = row.Split(',');
  35. var k = (CursorType)Enum.Parse(typeof(CursorType), info[0]);
  36. var v = new CursorInfo() {
  37. atlasOffset = int.Parse(info[1]),
  38. hotspot = new Vector2(int.Parse(info[2]), int.Parse(info[3])),
  39. };
  40. mapping[k] = v;
  41. }
  42. loaded = true;
  43. }
  44. /**
  45. * Texture for the current cursor.
  46. * If the cursor should be hidden, this will be null.
  47. */
  48. public virtual Texture2D Texture { get; protected set; }
  49. /**
  50. * Hotspot for the current cursor. (0, 0) indicates the top-left of the texture is the hotspot.
  51. * (1, 1) indicates the bottom-right.
  52. */
  53. public virtual Vector2 Hotspot { get; protected set; }
  54. private bool _hasMouse;
  55. /// <summary>
  56. /// True when the mouse is over the browser, false otherwise.
  57. /// </summary>
  58. public bool HasMouse {
  59. get {
  60. return _hasMouse;
  61. }
  62. set {
  63. _hasMouse = value;
  64. cursorChange();
  65. }
  66. }
  67. protected Texture2D normalTexture;
  68. protected Texture2D customTexture;
  69. public BrowserCursor() {
  70. Load();
  71. normalTexture = new Texture2D(size, size, TextureFormat.ARGB32, false);
  72. #if UNITY_EDITOR
  73. normalTexture.alphaIsTransparency = true;
  74. #endif
  75. SetActiveCursor(BrowserNative.CursorType.Pointer);
  76. }
  77. /// <summary>
  78. /// Switches the active cursor type. After calling this you can access the cursor image through this.Texture.
  79. /// </summary>
  80. /// <param name="type"></param>
  81. public virtual void SetActiveCursor(CursorType type) {
  82. if (type == CursorType.Custom) throw new ArgumentException("Use SetCustomCursor to set custom cursors.", "type");
  83. if (type == CursorType.None) {
  84. Texture = null;
  85. //Side note: if you copy down a bunch of transparent pixels and try to set the mouse cursor to that
  86. //both OS X and Windows fail to do what you'd expect.
  87. //Edit: OS X is now crashing for me if you try to do that.
  88. cursorChange();
  89. return;
  90. }
  91. var info = mapping[type];
  92. var pixelData = allCursors.GetPixels(info.atlasOffset * size, 0, size, size);
  93. Hotspot = info.hotspot;
  94. normalTexture.SetPixels(pixelData);
  95. normalTexture.Apply(true);
  96. Texture = normalTexture;
  97. cursorChange();
  98. }
  99. /// <summary>
  100. /// Sets a custom cursor.
  101. /// </summary>
  102. /// <param name="cursor">ARGB texture to set</param>
  103. /// <param name="hotspot"></param>
  104. public virtual void SetCustomCursor(Texture2D cursor, Vector2 hotspot) {
  105. var pixels = cursor.GetPixels32();
  106. //First off, is it completely blank? 'Cuz if so that can cause OS X to crash.
  107. var hasData = false;
  108. for (int i = 0; i < pixels.Length; i++) {
  109. if (pixels[i].a != 0) {
  110. hasData = true;
  111. break;
  112. }
  113. }
  114. if (!hasData) {
  115. //it's blank, so handle it like a regular blank cursor
  116. SetActiveCursor(CursorType.None);
  117. return;
  118. }
  119. if (!customTexture || customTexture.width != cursor.width || customTexture.height != cursor.height) {
  120. Object.Destroy(customTexture);
  121. customTexture = new Texture2D(cursor.width, cursor.height, TextureFormat.ARGB32, false);
  122. #if UNITY_EDITOR
  123. customTexture.alphaIsTransparency = true;
  124. #endif
  125. }
  126. customTexture.SetPixels32(pixels);
  127. customTexture.Apply(true);
  128. this.Hotspot = hotspot;
  129. Texture = customTexture;
  130. cursorChange();
  131. }
  132. }
  133. }