using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; using UnityEngine.UI.Extensions; namespace UnityEditor.UI { /// /// This script adds the Extensions UI menu options to the Unity Editor. /// static internal class ExtensionMenuOptions { #region Unity Builder section - Do not change unless UI Source (Editor\MenuOptions) changes #region Unity Builder properties - Do not change unless UI Source (Editor\MenuOptions) changes private const string kUILayerName = "UI"; private const float kWidth = 160f; private const float kThickHeight = 30f; private const float kThinHeight = 20f; private const string kStandardSpritePath = "UI/Skin/UISprite.psd"; private const string kBackgroundSpriteResourcePath = "UI/Skin/Background.psd"; private const string kInputFieldBackgroundPath = "UI/Skin/InputFieldBackground.psd"; private const string kKnobPath = "UI/Skin/Knob.psd"; private const string kCheckmarkPath = "UI/Skin/Checkmark.psd"; private static Vector2 s_ThickGUIElementSize = new Vector2(kWidth, kThickHeight); private static Vector2 s_ThinGUIElementSize = new Vector2(kWidth, kThinHeight); private static Vector2 s_ImageGUIElementSize = new Vector2(100f, 100f); private static Color s_DefaultSelectableColor = new Color(1f, 1f, 1f, 1f); private static Color s_TextColor = new Color(50f / 255f, 50f / 255f, 50f / 255f, 1f); #endregion #region Unity Builder methods - Do not change unless UI Source (Editor\MenuOptions) changes private static void SetPositionVisibleinSceneView(RectTransform canvasRTransform, RectTransform itemTransform) { // Find the best scene view SceneView sceneView = SceneView.lastActiveSceneView; if (sceneView == null && SceneView.sceneViews.Count > 0) sceneView = SceneView.sceneViews[0] as SceneView; // Couldn't find a SceneView. Don't set position. if (sceneView == null || sceneView.camera == null) return; // Create world space Plane from canvas position. Vector2 localPlanePosition; Camera camera = sceneView.camera; Vector3 position = Vector3.zero; if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRTransform, new Vector2(camera.pixelWidth / 2, camera.pixelHeight / 2), camera, out localPlanePosition)) { // Adjust for canvas pivot localPlanePosition.x = localPlanePosition.x + canvasRTransform.sizeDelta.x * canvasRTransform.pivot.x; localPlanePosition.y = localPlanePosition.y + canvasRTransform.sizeDelta.y * canvasRTransform.pivot.y; localPlanePosition.x = Mathf.Clamp(localPlanePosition.x, 0, canvasRTransform.sizeDelta.x); localPlanePosition.y = Mathf.Clamp(localPlanePosition.y, 0, canvasRTransform.sizeDelta.y); // Adjust for anchoring position.x = localPlanePosition.x - canvasRTransform.sizeDelta.x * itemTransform.anchorMin.x; position.y = localPlanePosition.y - canvasRTransform.sizeDelta.y * itemTransform.anchorMin.y; Vector3 minLocalPosition; minLocalPosition.x = canvasRTransform.sizeDelta.x * (0 - canvasRTransform.pivot.x) + itemTransform.sizeDelta.x * itemTransform.pivot.x; minLocalPosition.y = canvasRTransform.sizeDelta.y * (0 - canvasRTransform.pivot.y) + itemTransform.sizeDelta.y * itemTransform.pivot.y; Vector3 maxLocalPosition; maxLocalPosition.x = canvasRTransform.sizeDelta.x * (1 - canvasRTransform.pivot.x) - itemTransform.sizeDelta.x * itemTransform.pivot.x; maxLocalPosition.y = canvasRTransform.sizeDelta.y * (1 - canvasRTransform.pivot.y) - itemTransform.sizeDelta.y * itemTransform.pivot.y; position.x = Mathf.Clamp(position.x, minLocalPosition.x, maxLocalPosition.x); position.y = Mathf.Clamp(position.y, minLocalPosition.y, maxLocalPosition.y); } itemTransform.anchoredPosition = position; itemTransform.localRotation = Quaternion.identity; itemTransform.localScale = Vector3.one; } private static GameObject CreateUIElementRoot(string name, MenuCommand menuCommand, Vector2 size) { GameObject parent = menuCommand.context as GameObject; if (parent == null || parent.GetComponentInParent() == null) { parent = GetOrCreateCanvasGameObject(); } GameObject child = new GameObject(name); Undo.RegisterCreatedObjectUndo(child, "Create " + name); Undo.SetTransformParent(child.transform, parent.transform, "Parent " + child.name); GameObjectUtility.SetParentAndAlign(child, parent); RectTransform rectTransform = child.AddComponent(); rectTransform.sizeDelta = size; if (parent != menuCommand.context) // not a context click, so center in sceneview { SetPositionVisibleinSceneView(parent.GetComponent(), rectTransform); } Selection.activeGameObject = child; return child; } static GameObject CreateUIObject(string name, GameObject parent) { GameObject go = new GameObject(name); go.AddComponent(); GameObjectUtility.SetParentAndAlign(go, parent); return go; } static public void AddCanvas(MenuCommand menuCommand) { var go = CreateNewUI(); GameObjectUtility.SetParentAndAlign(go, menuCommand.context as GameObject); if (go.transform.parent as RectTransform) { RectTransform rect = go.transform as RectTransform; rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.anchoredPosition = Vector2.zero; rect.sizeDelta = Vector2.zero; } Selection.activeGameObject = go; } static public GameObject CreateNewUI() { // Root for the UI var root = new GameObject("Canvas"); root.layer = LayerMask.NameToLayer(kUILayerName); Canvas canvas = root.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; root.AddComponent(); root.AddComponent(); Undo.RegisterCreatedObjectUndo(root, "Create " + root.name); // if there is no event system add one... CreateEventSystem(false); return root; } public static void CreateEventSystem(MenuCommand menuCommand) { GameObject parent = menuCommand.context as GameObject; CreateEventSystem(true, parent); } private static void CreateEventSystem(bool select) { CreateEventSystem(select, null); } private static void CreateEventSystem(bool select, GameObject parent) { var esys = Object.FindObjectOfType(); if (esys == null) { var eventSystem = new GameObject("EventSystem"); GameObjectUtility.SetParentAndAlign(eventSystem, parent); esys = eventSystem.AddComponent(); eventSystem.AddComponent(); Undo.RegisterCreatedObjectUndo(eventSystem, "Create " + eventSystem.name); } if (select && esys != null) { Selection.activeGameObject = esys.gameObject; } } // Helper function that returns a Canvas GameObject; preferably a parent of the selection, or other existing Canvas. static public GameObject GetOrCreateCanvasGameObject() { GameObject selectedGo = Selection.activeGameObject; // Try to find a gameobject that is the selected GO or one if its parents. Canvas canvas = (selectedGo != null) ? selectedGo.GetComponentInParent() : null; if (canvas != null && canvas.gameObject.activeInHierarchy) return canvas.gameObject; // No canvas in selection or its parents? Then use just any canvas.. canvas = Object.FindObjectOfType(typeof(Canvas)) as Canvas; if (canvas != null && canvas.gameObject.activeInHierarchy) return canvas.gameObject; // No canvas in the scene at all? Then create a new one. return ExtensionMenuOptions.CreateNewUI(); } private static void SetDefaultColorTransitionValues(Selectable slider) { ColorBlock colors = slider.colors; colors.highlightedColor = new Color(0.882f, 0.882f, 0.882f); colors.pressedColor = new Color(0.698f, 0.698f, 0.698f); colors.disabledColor = new Color(0.521f, 0.521f, 0.521f); } private static void SetDefaultTextValues(Text lbl) { // Set text values we want across UI elements in default controls. // Don't set values which are the same as the default values for the Text component, // since there's no point in that, and it's good to keep them as consistent as possible. lbl.color = s_TextColor; } #endregion #endregion #region UI Extensions "Create" Menu items #region Scroll Snap controls [MenuItem("GameObject/UI/Extensions/Horizontal Scroll Snap", false)] static public void AddHorizontalScrollSnap(MenuCommand menuCommand) { GameObject horizontalScrollSnapRoot = CreateUIElementRoot("Horizontal Scroll Snap", menuCommand, s_ThickGUIElementSize); GameObject childContent = CreateUIObject("Content", horizontalScrollSnapRoot); GameObject childPage01 = CreateUIObject("Page_01", childContent); GameObject childText = CreateUIObject("Text", childPage01); // Set RectTransform to stretch RectTransform rectTransformScrollSnapRoot = horizontalScrollSnapRoot.GetComponent(); rectTransformScrollSnapRoot.anchorMin = new Vector2(0.5f, 0.5f); rectTransformScrollSnapRoot.anchorMax = new Vector2(0.5f, 0.5f); rectTransformScrollSnapRoot.anchoredPosition = Vector2.zero; rectTransformScrollSnapRoot.sizeDelta = new Vector2(300f, 150f); Image image = horizontalScrollSnapRoot.AddComponent(); image.sprite = AssetDatabase.GetBuiltinExtraResource(kBackgroundSpriteResourcePath); image.type = Image.Type.Sliced; image.color = new Color(1f, 1f, 1f, 0.392f); ScrollRect sr = horizontalScrollSnapRoot.AddComponent(); sr.vertical = false; sr.horizontal = true; horizontalScrollSnapRoot.AddComponent(); //Setup Content container RectTransform rectTransformContent = childContent.GetComponent(); rectTransformContent.anchorMin = Vector2.zero; rectTransformContent.anchorMax = new Vector2(1f, 1f); rectTransformContent.sizeDelta = Vector2.zero; sr.content = rectTransformContent; //Setup 1st Child Image pageImage = childPage01.AddComponent(); pageImage.sprite = AssetDatabase.GetBuiltinExtraResource(kStandardSpritePath); pageImage.type = Image.Type.Sliced; pageImage.color = s_DefaultSelectableColor; RectTransform rectTransformPage01 = childPage01.GetComponent(); rectTransformPage01.anchorMin = new Vector2(0f, 0.5f); rectTransformPage01.anchorMax = new Vector2(0f, 0.5f); rectTransformPage01.pivot = new Vector2(0f, 0.5f); //Setup Text on Page01 Text text = childText.AddComponent(); text.text = "Page_01"; text.alignment = TextAnchor.MiddleCenter; text.color = new Color(0.196f, 0.196f, 0.196f); //Setup Text 1st Child RectTransform rectTransformPage01Text = childText.GetComponent(); rectTransformPage01Text.anchorMin = new Vector2(0.5f, 0.5f); rectTransformPage01Text.anchorMax = new Vector2(0.5f, 0.5f); rectTransformPage01Text.pivot = new Vector2(0.5f, 0.5f); //Need to add example child components like in the Asset (SJ) Selection.activeGameObject = horizontalScrollSnapRoot; } [MenuItem("GameObject/UI/Extensions/Vertical Scroll Snap", false)] static public void AddVerticallScrollSnap(MenuCommand menuCommand) { GameObject verticalScrollSnapRoot = CreateUIElementRoot("Vertical Scroll Snap", menuCommand, s_ThickGUIElementSize); GameObject childContent = CreateUIObject("Content", verticalScrollSnapRoot); GameObject childPage01 = CreateUIObject("Page_01", childContent); GameObject childText = CreateUIObject("Text", childPage01); // Set RectTransform to stretch RectTransform rectTransformScrollSnapRoot = verticalScrollSnapRoot.GetComponent(); rectTransformScrollSnapRoot.anchorMin = new Vector2(0.5f, 0.5f); rectTransformScrollSnapRoot.anchorMax = new Vector2(0.5f, 0.5f); rectTransformScrollSnapRoot.anchoredPosition = Vector2.zero; rectTransformScrollSnapRoot.sizeDelta = new Vector2(300f, 150f); Image image = verticalScrollSnapRoot.AddComponent(); image.sprite = AssetDatabase.GetBuiltinExtraResource(kBackgroundSpriteResourcePath); image.type = Image.Type.Sliced; image.color = new Color(1f, 1f, 1f, 0.392f); ScrollRect sr = verticalScrollSnapRoot.AddComponent(); sr.vertical = true; sr.horizontal = false; verticalScrollSnapRoot.AddComponent(); //Setup Content container RectTransform rectTransformContent = childContent.GetComponent(); rectTransformContent.anchorMin = Vector2.zero; rectTransformContent.anchorMax = new Vector2(1f, 1f); //rectTransformContent.anchoredPosition = Vector2.zero; rectTransformContent.sizeDelta = Vector2.zero; sr.content = rectTransformContent; //Setup 1st Child Image pageImage = childPage01.AddComponent(); pageImage.sprite = AssetDatabase.GetBuiltinExtraResource(kStandardSpritePath); pageImage.type = Image.Type.Sliced; pageImage.color = s_DefaultSelectableColor; RectTransform rectTransformPage01 = childPage01.GetComponent(); rectTransformPage01.anchorMin = new Vector2(0.5f, 0f); rectTransformPage01.anchorMax = new Vector2(0.5f, 0f); rectTransformPage01.anchoredPosition = new Vector2(-rectTransformPage01.sizeDelta.x / 2, rectTransformPage01.sizeDelta.y / 2); //rectTransformPage01.anchoredPosition = Vector2.zero; //rectTransformPage01.sizeDelta = Vector2.zero; rectTransformPage01.pivot = new Vector2(0.5f, 0f); //Setup Text on Page01 Text text = childText.AddComponent(); text.text = "Page_01"; text.alignment = TextAnchor.MiddleCenter; text.color = new Color(0.196f, 0.196f, 0.196f); //Setup Text 1st Child RectTransform rectTransformPage01Text = childText.GetComponent(); rectTransformPage01Text.anchorMin = new Vector2(0.5f, 0.5f); rectTransformPage01Text.anchorMax = new Vector2(0.5f, 0.5f); //rectTransformPage01Text.anchoredPosition = Vector2.zero; //rectTransformPage01Text.sizeDelta = Vector2.zero; rectTransformPage01Text.pivot = new Vector2(0.5f, 0.5f); //Need to add example child components like in the Asset (SJ) Selection.activeGameObject = verticalScrollSnapRoot; } #region New ScrollSnapCode static public void FixedScrollSnapBase(MenuCommand menuCommand, string name, ScrollSnap.ScrollDirection direction, int itemVisible, int itemCount, Vector2 itemSize) { GameObject scrollSnapRoot = CreateUIElementRoot(name, menuCommand, s_ThickGUIElementSize); GameObject itemList = CreateUIObject("List", scrollSnapRoot); // Set RectTransform to stretch RectTransform rectTransformScrollSnapRoot = scrollSnapRoot.GetComponent(); rectTransformScrollSnapRoot.anchorMin = new Vector2(0.5f, 0.5f); rectTransformScrollSnapRoot.anchorMax = new Vector2(0.5f, 0.5f); rectTransformScrollSnapRoot.anchoredPosition = Vector2.zero; if (direction == ScrollSnap.ScrollDirection.Horizontal) { rectTransformScrollSnapRoot.sizeDelta = new Vector2(itemVisible * itemSize.x, itemSize.y); } else { rectTransformScrollSnapRoot.sizeDelta = new Vector2(itemSize.x, itemVisible * itemSize.y); } Image image = scrollSnapRoot.AddComponent(); image.sprite = AssetDatabase.GetBuiltinExtraResource(kBackgroundSpriteResourcePath); image.type = Image.Type.Sliced; image.color = new Color(1f, 1f, 1f, 1f); Mask listMask = scrollSnapRoot.AddComponent(); listMask.showMaskGraphic = false; ScrollRect scrollRect = scrollSnapRoot.AddComponent(); scrollRect.vertical = direction == ScrollSnap.ScrollDirection.Vertical; scrollRect.horizontal = direction == ScrollSnap.ScrollDirection.Horizontal; ScrollSnap scrollSnap = scrollSnapRoot.AddComponent(); scrollSnap.direction = direction; scrollSnap.itemsVisibleAtOnce = itemVisible; //Setup Content container RectTransform rectTransformContent = itemList.GetComponent(); rectTransformContent.anchorMin = Vector2.zero; rectTransformContent.anchorMax = new Vector2(1f, 1f); rectTransformContent.sizeDelta = Vector2.zero; scrollRect.content = rectTransformContent; //Setup Item list container if (direction == ScrollSnap.ScrollDirection.Horizontal) { itemList.AddComponent(); ContentSizeFitter sizeFitter = itemList.AddComponent(); sizeFitter.horizontalFit = ContentSizeFitter.FitMode.MinSize; } else { itemList.AddComponent(); ContentSizeFitter sizeFitter = itemList.AddComponent(); sizeFitter.verticalFit = ContentSizeFitter.FitMode.MinSize; } //Setup children for (var i = 0; i < itemCount; i++) { GameObject item = CreateUIObject(string.Format("Item_{0:00}", i), itemList); GameObject childText = CreateUIObject("Text", item); Image pageImage = item.AddComponent(); pageImage.sprite = AssetDatabase.GetBuiltinExtraResource(kStandardSpritePath); pageImage.type = Image.Type.Sliced; pageImage.color = s_DefaultSelectableColor; LayoutElement elementLayout = item.AddComponent(); if (direction == ScrollSnap.ScrollDirection.Horizontal) { elementLayout.minWidth = itemSize.x; } else { elementLayout.minHeight = itemSize.y; } RectTransform rectTransformPage01 = item.GetComponent(); rectTransformPage01.anchorMin = new Vector2(0f, 0.5f); rectTransformPage01.anchorMax = new Vector2(0f, 0.5f); rectTransformPage01.pivot = new Vector2(0f, 0.5f); //Setup Text on Page01 Text text = childText.AddComponent(); text.text = item.name; text.alignment = TextAnchor.MiddleCenter; text.color = new Color(0.196f, 0.196f, 0.196f); //Setup Text 1st Child RectTransform rectTransformPage01Text = childText.GetComponent(); rectTransformPage01Text.anchorMin = new Vector2(0.5f, 0.5f); rectTransformPage01Text.anchorMax = new Vector2(0.5f, 0.5f); rectTransformPage01Text.pivot = new Vector2(0.5f, 0.5f); } Selection.activeGameObject = scrollSnapRoot; } [MenuItem("GameObject/UI/Extensions/Fixed Item Scroll/Snap Horizontal Single Item", false)] static public void AddFixedItemScrollSnapHorizontalSingle(MenuCommand menuCommand) { FixedScrollSnapBase(menuCommand, "Scroll Snap Horizontal Single", ScrollSnap.ScrollDirection.Horizontal, 1, 3, new Vector2(100, 100)); } [MenuItem("GameObject/UI/Extensions/Fixed Item Scroll/Snap Horizontal Multiple Items", false)] static public void AddFixedItemScrollSnapHorizontalMultiple(MenuCommand menuCommand) { FixedScrollSnapBase(menuCommand, "Scroll Snap Horizontal Multiple", ScrollSnap.ScrollDirection.Horizontal, 3, 15, new Vector2(100, 100)); } [MenuItem("GameObject/UI/Extensions/Fixed Item Scroll/Snap Vertical Single Item", false)] static public void AddFixedItemScrollSnapVerticalSingle(MenuCommand menuCommand) { FixedScrollSnapBase(menuCommand, "Scroll Snap Vertical Multiple", ScrollSnap.ScrollDirection.Vertical, 1, 3, new Vector2(100, 100)); } [MenuItem("GameObject/UI/Extensions/Fixed Item Scroll/Snap Vertical Multiple Items", false)] static public void AddFixedItemScrollSnapVerticalMultiple(MenuCommand menuCommand) { FixedScrollSnapBase(menuCommand, "Scroll Snap Vertical Multiple", ScrollSnap.ScrollDirection.Vertical, 3, 15, new Vector2(100, 100)); } #endregion #endregion #region UIVertical Scroller [MenuItem("GameObject/UI/Extensions/UI Vertical Scroller", false)] static public void AddUIVerticallScroller(MenuCommand menuCommand) { GameObject uiVerticalScrollerRoot = CreateUIElementRoot("UI Vertical Scroller", menuCommand, s_ThickGUIElementSize); GameObject uiScrollerCenter = CreateUIObject("Center", uiVerticalScrollerRoot); GameObject childContent = CreateUIObject("Content", uiVerticalScrollerRoot); // Set RectTransform to stretch RectTransform rectTransformScrollSnapRoot = uiVerticalScrollerRoot.GetComponent(); rectTransformScrollSnapRoot.anchorMin = new Vector2(0.5f, 0.5f); rectTransformScrollSnapRoot.anchorMax = new Vector2(0.5f, 0.5f); rectTransformScrollSnapRoot.anchoredPosition = Vector2.zero; rectTransformScrollSnapRoot.sizeDelta = new Vector2(500f, 150f); // Add required ScrollRect ScrollRect sr = uiVerticalScrollerRoot.AddComponent(); sr.vertical = true; sr.horizontal = false; sr.movementType = ScrollRect.MovementType.Unrestricted; var uiscr = uiVerticalScrollerRoot.AddComponent(); //Setup container center point RectTransform rectTransformCenter = uiScrollerCenter.GetComponent(); rectTransformCenter.anchorMin = new Vector2(0f, 0.3f); rectTransformCenter.anchorMax = new Vector2(1f, 0.6f); rectTransformCenter.sizeDelta = Vector2.zero; uiscr._center = uiScrollerCenter.GetComponent(); //Setup Content container RectTransform rectTransformContent = childContent.GetComponent(); rectTransformContent.anchorMin = Vector2.zero; rectTransformContent.anchorMax = new Vector2(1f, 1f); rectTransformContent.sizeDelta = Vector2.zero; sr.content = rectTransformContent; // Add sample children for (int i = 0; i < 10; i++) { GameObject childPage = CreateUIObject("Page_" + i, childContent); GameObject childText = CreateUIObject("Text", childPage); //Setup 1st Child Image pageImage = childPage.AddComponent(); pageImage.sprite = AssetDatabase.GetBuiltinExtraResource(kStandardSpritePath); pageImage.type = Image.Type.Sliced; pageImage.color = s_DefaultSelectableColor; RectTransform rectTransformPage = childPage.GetComponent(); rectTransformPage.anchorMin = new Vector2(0f, 0.5f); rectTransformPage.anchorMax = new Vector2(1f, 0.5f); rectTransformPage.sizeDelta = new Vector2(0f, 80f); rectTransformPage.pivot = new Vector2(0.5f, 0.5f); rectTransformPage.localPosition = new Vector3(0, 80 * i, 0); childPage.AddComponent