No Description
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.

GridPaintTargetsDropdown.cs 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. using System;
  2. using UnityEditor.Experimental;
  3. using UnityEngine;
  4. namespace UnityEditor.Tilemaps
  5. {
  6. internal class GridPaintTargetsDropdown : PopupWindowContent
  7. {
  8. private class Styles
  9. {
  10. public class IconState
  11. {
  12. public GUIContent visible;
  13. public GUIContent hidden;
  14. public GUIContent ping;
  15. }
  16. public GUIStyle menuItem = "MenuItem";
  17. public GUIContent backIcon = EditorGUIUtility.TrIconContent("tab_next");
  18. public static readonly Color backgroundColor = EditorResources.GetStyle("game-object-tree-view-scene-visibility")
  19. .GetColor("background-color");
  20. public static readonly Color hoveredBackgroundColor = EditorResources.GetStyle("game-object-tree-view-scene-visibility")
  21. .GetColor("-unity-object-hovered-color");
  22. public static readonly Color selectedBackgroundColor = EditorResources.GetStyle("game-object-tree-view-scene-visibility")
  23. .GetColor("-unity-object-selected-color");
  24. public static readonly Color selectedNoFocusBackgroundColor = EditorResources.GetStyle("game-object-tree-view-scene-visibility")
  25. .GetColor("-unity-object-selected-no-focus-color");
  26. public static readonly GUIStyle sceneVisibilityStyle = "SceneVisibility";
  27. public static readonly IconState iconNormal = new()
  28. {
  29. visible = EditorGUIUtility.TrIconContent("scenevis_visible", "Click to hide Target in SceneView"),
  30. hidden = EditorGUIUtility.TrIconContent("scenevis_hidden", "Click to show Target in SceneView"),
  31. ping = EditorGUIUtility.TrIconContent("Packages/com.unity.2d.tilemap/Editor/Icons/EditorUI.Target.png", "Click to ping Target in Hierarchy"),
  32. };
  33. public static readonly IconState iconHovered = new()
  34. {
  35. visible = EditorGUIUtility.TrIconContent("scenevis_visible_hover", "Click to hide Target in SceneView"),
  36. hidden = EditorGUIUtility.TrIconContent("scenevis_hidden_hover", "Click to show Target in SceneView"),
  37. ping = EditorGUIUtility.TrIconContent("Packages/com.unity.2d.tilemap/Editor/Icons/EditorUI.TargetHover.png", "Click to ping Target in Hierarchy"),
  38. };
  39. public static Color GetItemBackgroundColor(bool isHovered, bool isSelected, bool isFocused)
  40. {
  41. if (isSelected)
  42. {
  43. if (isFocused)
  44. return selectedBackgroundColor;
  45. return selectedNoFocusBackgroundColor;
  46. }
  47. if (isHovered)
  48. return hoveredBackgroundColor;
  49. return backgroundColor;
  50. }
  51. }
  52. internal static string k_CreateNewPaintTargetName = L10n.Tr("Create New Tilemap");
  53. private static Styles s_Styles;
  54. private IFlexibleMenuItemProvider m_ItemProvider;
  55. private FlexibleMenuModifyItemUI m_ModifyItemUI;
  56. private readonly Action<int, object> m_ItemClickedCallback;
  57. private readonly Action<int, Rect> m_ItemHoveredCallback;
  58. private Vector2 m_ScrollPosition = Vector2.zero;
  59. private bool m_ShowAddNewPresetItem;
  60. private int m_HoverIndex;
  61. private int[] m_SeperatorIndices;
  62. private float m_CachedWidth = -1f;
  63. private float m_MinTextWidth;
  64. private const float LineHeight = 18f;
  65. private const float SeperatorHeight = 8f;
  66. private int maxIndex { get { return m_ShowAddNewPresetItem ? m_ItemProvider.Count() : m_ItemProvider.Count() - 1; } }
  67. public int selectedIndex { get; set; }
  68. protected float minTextWidth { get { return m_MinTextWidth; } set { m_MinTextWidth = value; ClearCachedWidth(); } }
  69. internal class MenuItemProvider : IFlexibleMenuItemProvider
  70. {
  71. public int Count()
  72. {
  73. return GridPaintingState.validTargets != null ? GridPaintingState.validTargets.Length + 1 : 1;
  74. }
  75. public object GetItem(int index)
  76. {
  77. if (GridPaintingState.validTargets != null && index < GridPaintingState.validTargets.Length)
  78. return GridPaintingState.validTargets[index];
  79. return GridPaintingState.scenePaintTarget;
  80. }
  81. public int Add(object obj)
  82. {
  83. throw new NotImplementedException();
  84. }
  85. public void Replace(int index, object newPresetObject)
  86. {
  87. throw new NotImplementedException();
  88. }
  89. public void Remove(int index)
  90. {
  91. throw new NotImplementedException();
  92. }
  93. public object Create()
  94. {
  95. throw new NotImplementedException();
  96. }
  97. public void Move(int index, int destIndex, bool insertAfterDestIndex)
  98. {
  99. throw new NotImplementedException();
  100. }
  101. public string GetName(int index)
  102. {
  103. if (GridPaintingState.validTargets != null
  104. && index < GridPaintingState.validTargets.Length)
  105. {
  106. return GridPaintingState.validTargets[index].name;
  107. }
  108. return "Create New Tilemap";
  109. }
  110. public bool IsModificationAllowed(int index)
  111. {
  112. return false;
  113. }
  114. public int[] GetSeperatorIndices()
  115. {
  116. if (GridPaintingState.validTargets != null)
  117. return new int[] { GridPaintingState.validTargets.Length - 1 };
  118. return new int[] { -1 };
  119. }
  120. }
  121. // itemClickedCallback arguments is clicked index, clicked item object
  122. public GridPaintTargetsDropdown(IFlexibleMenuItemProvider itemProvider
  123. , int selectionIndex
  124. , FlexibleMenuModifyItemUI modifyItemUi
  125. , Action<int, object> itemClickedCallback
  126. , Action<int, Rect> itemHoveredCallback
  127. , float minWidth)
  128. {
  129. m_ItemProvider = itemProvider;
  130. m_ModifyItemUI = modifyItemUi;
  131. m_ItemClickedCallback = itemClickedCallback;
  132. m_ItemHoveredCallback = itemHoveredCallback;
  133. m_SeperatorIndices = m_ItemProvider.GetSeperatorIndices();
  134. selectedIndex = selectionIndex;
  135. m_ShowAddNewPresetItem = m_ModifyItemUI != null;
  136. m_MinTextWidth = minWidth;
  137. }
  138. public override Vector2 GetWindowSize()
  139. {
  140. return CalcSize();
  141. }
  142. public override void OnGUI(Rect rect)
  143. {
  144. if (s_Styles == null)
  145. s_Styles = new Styles();
  146. Event evt = Event.current;
  147. Rect contentRect = new Rect(0, 0, 1, CalcSize().y);
  148. m_ScrollPosition = GUI.BeginScrollView(rect, m_ScrollPosition, contentRect);
  149. {
  150. float curY = 0f;
  151. for (int i = 0; i <= maxIndex; ++i)
  152. {
  153. var itemControlID = i + 1000000;
  154. var fullRect = new Rect(0, curY, rect.width, LineHeight);
  155. var visRect = new Rect(0, curY, 16, LineHeight);
  156. var pingRect = new Rect(16, curY, 16, LineHeight);
  157. var backRect = new Rect(0, curY, 32, LineHeight);
  158. var arrowRect = new Rect(rect.width - 16 - 1, curY, 16, LineHeight);
  159. var itemRect = new Rect(16 + 16, curY, rect.width - 16 - 16, LineHeight);
  160. var addSeparator = Array.IndexOf(m_SeperatorIndices, i) >= 0;
  161. var isCreate = i == maxIndex;
  162. // Handle event
  163. switch (evt.type)
  164. {
  165. case EventType.Repaint:
  166. bool hover = false;
  167. if (m_HoverIndex == i)
  168. {
  169. if (fullRect.Contains(evt.mousePosition))
  170. hover = true;
  171. else
  172. m_HoverIndex = -1;
  173. }
  174. var isItemVisible = IsVisible(i) || isCreate;
  175. using (new GUI.BackgroundColorScope(Styles.GetItemBackgroundColor(hover, hover, hover)))
  176. {
  177. if (!isCreate)
  178. GUI.Label(backRect, GUIContent.none, GameObjectTreeViewGUI.GameObjectStyles.hoveredItemBackgroundStyle);
  179. }
  180. if ((hover || !isItemVisible) && !isCreate)
  181. {
  182. var isVisHover = visRect.Contains(evt.mousePosition);
  183. var visIconState = isVisHover
  184. ? Styles.iconHovered
  185. : Styles.iconNormal;
  186. var visIcon = isItemVisible ? visIconState.visible : visIconState.hidden;
  187. GUI.Button(visRect, visIcon, Styles.sceneVisibilityStyle);
  188. }
  189. if (hover && !isCreate)
  190. {
  191. var isPingHover = pingRect.Contains(evt.mousePosition);
  192. var pingIconState = isPingHover
  193. ? Styles.iconHovered
  194. : Styles.iconNormal;
  195. GUI.Button(pingRect, pingIconState.ping, Styles.sceneVisibilityStyle);
  196. }
  197. using (new EditorGUI.DisabledScope(!isItemVisible))
  198. {
  199. s_Styles.menuItem.Draw(isCreate ? fullRect : itemRect, GUIContent.Temp(m_ItemProvider.GetName(i)), hover, false, i == selectedIndex, false);
  200. }
  201. if (isCreate)
  202. {
  203. GUI.Button(arrowRect, s_Styles.backIcon, Styles.sceneVisibilityStyle);
  204. }
  205. if (addSeparator)
  206. {
  207. const float margin = 4f;
  208. Rect seperatorRect = new Rect(fullRect.x + margin, fullRect.y + fullRect.height + SeperatorHeight * 0.5f, fullRect.width - 2 * margin, 1);
  209. DrawRect(seperatorRect, (EditorGUIUtility.isProSkin) ? new Color(0.32f, 0.32f, 0.32f, 1.333f) : new Color(0.6f, 0.6f, 0.6f, 1.333f)); // dark : light
  210. }
  211. break;
  212. case EventType.MouseDown:
  213. if (evt.button == 0 && visRect.Contains(evt.mousePosition))
  214. {
  215. GUIUtility.hotControl = itemControlID;
  216. if (evt.clickCount == 1)
  217. {
  218. GUIUtility.hotControl = 0;
  219. ToggleVisibility(i, !evt.alt);
  220. evt.Use();
  221. }
  222. }
  223. if (evt.button == 0 && pingRect.Contains(evt.mousePosition))
  224. {
  225. GUIUtility.hotControl = itemControlID;
  226. if (evt.clickCount == 1)
  227. {
  228. GUIUtility.hotControl = 0;
  229. PingItem(i);
  230. evt.Use();
  231. }
  232. }
  233. if (evt.button == 0 && itemRect.Contains(evt.mousePosition) && IsVisible(i))
  234. {
  235. GUIUtility.hotControl = itemControlID;
  236. if (evt.clickCount == 1)
  237. {
  238. GUIUtility.hotControl = 0;
  239. SelectItem(i);
  240. editorWindow.Close();
  241. evt.Use();
  242. }
  243. }
  244. break;
  245. case EventType.MouseUp:
  246. if (GUIUtility.hotControl == itemControlID)
  247. {
  248. GUIUtility.hotControl = 0;
  249. }
  250. break;
  251. case EventType.MouseMove:
  252. if (fullRect.Contains(evt.mousePosition))
  253. {
  254. m_HoverIndex = i;
  255. HoverItem(itemRect, m_HoverIndex);
  256. }
  257. else if (m_HoverIndex == i)
  258. {
  259. m_HoverIndex = -1;
  260. }
  261. Repaint();
  262. break;
  263. }
  264. curY += LineHeight;
  265. if (addSeparator)
  266. curY += SeperatorHeight;
  267. } // end foreach item
  268. } GUI.EndScrollView();
  269. }
  270. private void SelectItem(int index)
  271. {
  272. selectedIndex = index;
  273. if (m_ItemClickedCallback != null && index >= 0)
  274. m_ItemClickedCallback(index, m_ItemProvider.GetItem(index));
  275. }
  276. private void HoverItem(Rect rect, int index)
  277. {
  278. if (m_ItemHoveredCallback != null && index >= 0)
  279. m_ItemHoveredCallback(index, rect);
  280. }
  281. private bool IsVisible(int index)
  282. {
  283. var obj = m_ItemProvider.GetItem(index) as GameObject;
  284. if (obj != null)
  285. return !SceneVisibilityManager.instance.IsHidden(obj);
  286. return false;
  287. }
  288. private void ToggleVisibility(int index, bool includeDescendants)
  289. {
  290. var obj = m_ItemProvider.GetItem(index) as GameObject;
  291. if (obj != null)
  292. SceneVisibilityManager.instance.ToggleVisibility(obj, includeDescendants);
  293. }
  294. private void PingItem(int index)
  295. {
  296. var obj = m_ItemProvider.GetItem(index) as UnityEngine.Object;
  297. if (obj != null)
  298. EditorGUIUtility.PingObject(obj);
  299. }
  300. protected Vector2 CalcSize()
  301. {
  302. float height = (maxIndex + 1) * LineHeight + m_SeperatorIndices.Length * SeperatorHeight;
  303. if (m_CachedWidth < 0)
  304. m_CachedWidth = Math.Max(m_MinTextWidth, CalcWidth());
  305. return new Vector2(m_CachedWidth, height);
  306. }
  307. private void ClearCachedWidth()
  308. {
  309. m_CachedWidth = -1f;
  310. }
  311. private float CalcWidth()
  312. {
  313. if (s_Styles == null)
  314. s_Styles = new Styles();
  315. float maxWidth = 0;
  316. for (int i = 0; i < m_ItemProvider.Count(); ++i)
  317. {
  318. float w = s_Styles.menuItem.CalcSize(GUIContent.Temp(m_ItemProvider.GetName(i))).x;
  319. maxWidth = Mathf.Max(w, maxWidth);
  320. }
  321. const float rightMargin = 6f;
  322. return maxWidth + rightMargin;
  323. }
  324. private void DrawRect(Rect rect, Color color)
  325. {
  326. if (Event.current.type != EventType.Repaint)
  327. return;
  328. Color orgColor = GUI.color;
  329. GUI.color = GUI.color * color;
  330. GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);
  331. GUI.color = orgColor;
  332. }
  333. private void Repaint()
  334. {
  335. HandleUtility.Repaint(); // repaints current guiview (needs rename)
  336. }
  337. }
  338. }