暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SpriteSelector.cs 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. using System;
  2. using UnityEditor.U2D.Common;
  3. using UnityEditorInternal;
  4. using UnityEngine;
  5. namespace UnityEditor.U2D
  6. {
  7. internal class SpriteSelector
  8. {
  9. int m_SelectedSprite = 0;
  10. Sprite[] m_SpriteList = null;
  11. Texture[] m_Thumbnails;
  12. Vector2 m_ScrollPos;
  13. int m_WindowSize = 0;
  14. int m_ImageSize = 4;
  15. bool m_Inspector = true;
  16. public bool inspector
  17. {
  18. get => m_Inspector;
  19. set => m_Inspector = value;
  20. }
  21. public int imageSize
  22. {
  23. get { return m_ImageSize; }
  24. set { m_ImageSize = value; }
  25. }
  26. public int windowSize
  27. {
  28. get { return m_WindowSize; }
  29. set { m_WindowSize = value; }
  30. }
  31. public int selectedIndex
  32. {
  33. get { return m_SelectedSprite; }
  34. set { m_SelectedSprite = value; }
  35. }
  36. public bool hasSprites
  37. {
  38. get { return (m_SpriteList != null) && (m_SpriteList.Length != 0); }
  39. }
  40. internal static class Styles
  41. {
  42. public static GUIStyle gridList = "GridList";
  43. public static GUIContent spriteList = EditorGUIUtility.TrTextContent("Sprite Variant");
  44. public static GUIContent missingSprites = EditorGUIUtility.TrTextContent("No brushes defined.");
  45. public static GUIStyle localGrid = null;
  46. }
  47. public SpriteSelector()
  48. {
  49. m_SpriteList = null;
  50. }
  51. public void SetCustomSize(int windowSizer, int imageSizer)
  52. {
  53. m_WindowSize = windowSizer;
  54. m_ImageSize = imageSizer;
  55. m_Inspector = false;
  56. }
  57. public void ResetSize()
  58. {
  59. m_WindowSize = 0;
  60. m_ImageSize = 64;
  61. m_Inspector = true;
  62. }
  63. public void UpdateSprites(Sprite[] sprites)
  64. {
  65. m_SpriteList = sprites;
  66. UpdateSelection(0);
  67. }
  68. public void UpdateSelection(int newSelectedBrush)
  69. {
  70. m_SelectedSprite = newSelectedBrush;
  71. }
  72. private static int CalcTotalHorizSpacing(int xCount, GUIStyle style, GUIStyle firstStyle, GUIStyle midStyle, GUIStyle lastStyle)
  73. {
  74. if (xCount < 2)
  75. return 0;
  76. if (xCount == 2)
  77. return Mathf.Max(firstStyle.margin.right, lastStyle.margin.left);
  78. int internalSpace = Mathf.Max(midStyle.margin.left, midStyle.margin.right);
  79. int horizSpace = Mathf.Max(firstStyle.margin.right, midStyle.margin.left) + Mathf.Max(midStyle.margin.right, lastStyle.margin.left) + internalSpace * (xCount - 3);
  80. return horizSpace;
  81. }
  82. // Helper function: Get all mouse rects
  83. private static Rect[] CalcMouseRects(Rect position, GUIContent[] contents, int xCount, float elemWidth, float elemHeight, GUIStyle style, GUIStyle firstStyle, GUIStyle midStyle, GUIStyle lastStyle, bool addBorders, GUI.ToolbarButtonSize buttonSize)
  84. {
  85. int count = contents.Length;
  86. int x = 0;
  87. float xPos = position.xMin, yPos = position.yMin;
  88. GUIStyle currentStyle = style;
  89. Rect[] retval = new Rect[count];
  90. if (count > 1)
  91. currentStyle = firstStyle;
  92. for (int i = 0; i < count; i++)
  93. {
  94. float w = 0;
  95. switch (buttonSize)
  96. {
  97. case GUI.ToolbarButtonSize.Fixed:
  98. w = elemWidth;
  99. break;
  100. case GUI.ToolbarButtonSize.FitToContents:
  101. w = currentStyle.CalcSize(contents[i]).x;
  102. break;
  103. }
  104. if (!addBorders)
  105. retval[i] = new Rect(xPos, yPos, w, elemHeight);
  106. else
  107. retval[i] = currentStyle.margin.Add(new Rect(xPos, yPos, w, elemHeight));
  108. //we round the values to the dpi-aware pixel grid
  109. retval[i] = GUIUtility.AlignRectToDevice(retval[i]);
  110. GUIStyle nextStyle = midStyle;
  111. if (i == count - 2 || i == xCount - 2)
  112. nextStyle = lastStyle;
  113. xPos = retval[i].xMax + Mathf.Max(currentStyle.margin.right, nextStyle.margin.left);
  114. x++;
  115. if (x >= xCount)
  116. {
  117. x = 0;
  118. yPos += elemHeight + Mathf.Max(style.margin.top, style.margin.bottom);
  119. xPos = position.xMin;
  120. nextStyle = firstStyle;
  121. }
  122. currentStyle = nextStyle;
  123. }
  124. return retval;
  125. }
  126. static void DrawRectangleOutline(Rect rect, Color color)
  127. {
  128. Color currentColor = Handles.color;
  129. Handles.color = color;
  130. // Draw viewport outline
  131. Vector3[] points = new Vector3[5];
  132. points[0] = new Vector3(rect.x, rect.y, 0.0f);
  133. points[1] = new Vector3(rect.x + rect.width, rect.y, 0.0f);
  134. points[2] = new Vector3(rect.x + rect.width, rect.y + rect.height, 0.0f);
  135. points[3] = new Vector3(rect.x, rect.y + rect.height, 0.0f);
  136. points[4] = new Vector3(rect.x, rect.y, 0.0f);
  137. Handles.DrawPolyLine(points);
  138. Handles.color = currentColor;
  139. }
  140. // Make a button grid
  141. private static int DoButtonGrid(Rect position, int selected, GUIContent[] contents, string[] controlNames, int xCount, GUIStyle style, GUIStyle firstStyle, GUIStyle midStyle, GUIStyle lastStyle, GUI.ToolbarButtonSize buttonSize, bool[] contentsEnabled = null)
  142. {
  143. int count = contents.Length;
  144. if (count == 0)
  145. return selected;
  146. if (xCount <= 0)
  147. {
  148. Debug.LogWarning("You are trying to create a SelectionGrid with zero or less elements to be displayed in the horizontal direction. Set xCount to a positive value.");
  149. return selected;
  150. }
  151. if (contentsEnabled != null && contentsEnabled.Length != count)
  152. throw new ArgumentException("contentsEnabled");
  153. // Figure out how large each element should be
  154. int rows = count / xCount;
  155. if (count % xCount != 0)
  156. rows++;
  157. float totalHorizSpacing = CalcTotalHorizSpacing(xCount, style, firstStyle, midStyle, lastStyle);
  158. float totalVerticalSpacing = Mathf.Max(style.margin.top, style.margin.bottom) * (rows - 1);
  159. float elemWidth = (position.width - totalHorizSpacing) / xCount;
  160. float elemHeight = (position.height - totalVerticalSpacing) / rows;
  161. if (style.fixedWidth != 0)
  162. elemWidth = style.fixedWidth;
  163. if (style.fixedHeight != 0)
  164. elemHeight = style.fixedHeight;
  165. Rect[] buttonRects = CalcMouseRects(position, contents, xCount, elemWidth, elemHeight, style, firstStyle, midStyle, lastStyle, false, buttonSize);
  166. GUIStyle selectedButtonStyle = null;
  167. int selectedButtonID = 0;
  168. for (int buttonIndex = 0; buttonIndex < count; ++buttonIndex)
  169. {
  170. bool wasEnabled = GUI.enabled;
  171. GUI.enabled &= (contentsEnabled == null || contentsEnabled[buttonIndex]);
  172. var buttonRect = buttonRects[buttonIndex];
  173. var content = contents[buttonIndex];
  174. if (controlNames != null)
  175. GUI.SetNextControlName(controlNames[buttonIndex]);
  176. var id = GUIUtility.GetControlID("ButtonGrid".GetHashCode(), FocusType.Passive, buttonRect);
  177. if (buttonIndex == selected)
  178. selectedButtonID = id;
  179. switch (Event.current.GetTypeForControl(id))
  180. {
  181. case EventType.MouseDown:
  182. if (buttonRect.Contains(Event.current.mousePosition))
  183. {
  184. GUIUtility.hotControl = id;
  185. Event.current.Use();
  186. }
  187. break;
  188. case EventType.MouseDrag:
  189. if (GUIUtility.hotControl == id)
  190. Event.current.Use();
  191. break;
  192. case EventType.MouseUp:
  193. if (GUIUtility.hotControl == id)
  194. {
  195. GUIUtility.hotControl = 0;
  196. Event.current.Use();
  197. GUI.changed = true;
  198. return buttonIndex;
  199. }
  200. break;
  201. case EventType.Repaint:
  202. var buttonStyle = count == 1 ? style : (buttonIndex == 0 ? firstStyle : (buttonIndex == count - 1 ? lastStyle : midStyle));
  203. var isSelected = selected == buttonIndex;
  204. if (!isSelected)
  205. {
  206. GUI.DrawTexture(buttonRect, content.image, ScaleMode.ScaleToFit, true);
  207. GUI.Label(new Rect(buttonRect.x, buttonRect.y, 32, 32), buttonIndex.ToString());
  208. }
  209. else
  210. selectedButtonStyle = buttonStyle;
  211. break;
  212. }
  213. GUI.enabled = wasEnabled;
  214. }
  215. // draw selected button at the end so it overflows nicer
  216. if (selectedButtonStyle != null)
  217. {
  218. var buttonRect = buttonRects[selected];
  219. var content = contents[selected];
  220. var wasEnabled = GUI.enabled;
  221. GUI.enabled &= (contentsEnabled == null || contentsEnabled[selected]);
  222. GUI.DrawTexture(new Rect(buttonRect.x + 4, buttonRect.y + 4, buttonRect.width - 8, buttonRect.height - 8), content.image, ScaleMode.ScaleToFit, true);
  223. DrawRectangleOutline(buttonRect, GUI.skin.settings.selectionColor);
  224. GUI.Label(new Rect(buttonRect.x, buttonRect.y, 32, 32), selected.ToString());
  225. GUI.enabled = wasEnabled;
  226. }
  227. return selected;
  228. }
  229. // Get Temp Texture Contents for Sprites.
  230. private static GUIContent[] Temp(Texture[] images)
  231. {
  232. GUIContent[] retval = new GUIContent[images.Length];
  233. for (int i = 0; i < images.Length; i++)
  234. {
  235. retval[i] = new GUIContent(images[i]);
  236. }
  237. return retval;
  238. }
  239. public Sprite GetActiveSprite()
  240. {
  241. if (m_SelectedSprite >= m_SpriteList.Length)
  242. m_SelectedSprite = 0;
  243. return m_SpriteList[m_SelectedSprite];
  244. }
  245. public bool ShowGUI(int selectedIndex)
  246. {
  247. bool repaint = false;
  248. if (m_SpriteList == null || m_SpriteList.Length == 0)
  249. return false;
  250. int approxSize = 64;
  251. int approxHolderSize = approxSize + 2;
  252. if (Styles.localGrid == null)
  253. {
  254. Styles.localGrid = new GUIStyle(Styles.gridList);
  255. }
  256. // 64, 56, 36, 28
  257. int[] actualSizes = new int[] {0, 64, 48, 32, 24};
  258. int clamped = Math.Min(imageSize, 4);
  259. int actualSize = actualSizes[clamped];
  260. Styles.localGrid.fixedWidth = actualSize;
  261. Styles.localGrid.fixedHeight = actualSize;
  262. m_SelectedSprite = (selectedIndex > m_SpriteList.Length) ? 0 : selectedIndex;
  263. int wwidth = m_WindowSize == 0 ? (int)InternalEditorBridge.GetEditorGUILayoutLastRect().width : (int)m_WindowSize;
  264. int viewwidth = (int)(wwidth - EditorGUIUtility.labelWidth - approxSize);
  265. int columns = (int)(viewwidth) / actualSize;
  266. columns = columns <= 0 ? 1 : columns;
  267. int rows = (int)Mathf.Ceil((m_SpriteList.Length + columns - 1) / columns);
  268. int lyColumns = inspector ? (approxHolderSize) : approxHolderSize;
  269. EditorGUILayout.BeginHorizontal("box");
  270. {
  271. GUILayout.Label(Styles.spriteList, EditorStyles.label, GUILayout.Width(EditorGUIUtility.labelWidth - 5));
  272. GUILayout.BeginVertical("box", new GUILayoutOption[] { GUILayout.Height(lyColumns) } );
  273. {
  274. m_ScrollPos = EditorGUILayout.BeginScrollView(m_ScrollPos, new GUILayoutOption[] { GUILayout.Height(lyColumns) });
  275. int newBrush = SpriteSelectionGrid(m_SelectedSprite, m_SpriteList, actualSize, Styles.localGrid, Styles.missingSprites, columns, rows);
  276. if (newBrush != m_SelectedSprite)
  277. {
  278. UpdateSelection(newBrush);
  279. repaint = true;
  280. }
  281. EditorGUILayout.EndScrollView();
  282. }
  283. GUILayout.EndVertical();
  284. }
  285. EditorGUILayout.EndHorizontal();
  286. EditorGUILayout.Space();
  287. return repaint;
  288. }
  289. int SpriteSelectionGrid(int selected, Sprite[] sprites, int approxSize, GUIStyle style, GUIContent emptyString, int columns, int rows)
  290. {
  291. int retval = 0;
  292. if (sprites.Length != 0)
  293. {
  294. Rect r = GUILayoutUtility.GetRect((float)columns * approxSize, (float)rows * approxSize);
  295. Event evt = Event.current;
  296. if (evt.type == EventType.MouseDown && evt.clickCount == 2 && r.Contains(evt.mousePosition))
  297. evt.Use();
  298. m_Thumbnails = PreviewTexturesFromSprites(sprites);
  299. retval = DoButtonGrid(r, selected, Temp(m_Thumbnails), null, (int)columns, style, style, style, style, GUI.ToolbarButtonSize.Fixed);
  300. }
  301. else
  302. GUILayout.Label(emptyString);
  303. return retval;
  304. }
  305. internal static Texture[] PreviewTexturesFromSprites(Sprite[] sprites)
  306. {
  307. Texture[] retval = new Texture[sprites.Length];
  308. for (int i = 0; i < sprites.Length; i++)
  309. retval[i] = AssetPreview.GetAssetPreview(sprites[i]) ?? Texture2D.whiteTexture;
  310. return retval;
  311. }
  312. }
  313. } //namespace