using System.Text; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; using VMM.UI.Components; namespace VMM.UI.Helpers { internal static class UIBuilder { const string TABS_CONTAINER_PATH = "Canvas/Margins"; const string BUTTON_PATH = TABS_CONTAINER_PATH + "/Main Menu/Play Button"; const string OPTIONS_PATH = TABS_CONTAINER_PATH + "/Options"; const string DIVIDER_PATH = OPTIONS_PATH + "/Divider"; const string SLIDER_PATH = OPTIONS_PATH + "/Master Volume"; public static RectTransform CreateTab(string name, float x, float y) { if (!InMainMenu()) { Core.Logger.Warning("Tried Creating UI outside Main Menu, Aborting."); return null; } var tabObj = new GameObject(name, typeof(RectTransform)); tabObj.transform.SetParent(GameObject.Find(TABS_CONTAINER_PATH).transform, false); tabObj.layer = LayerMask.NameToLayer("UI"); tabObj.SetActive(false); var tabRect = tabObj.GetComponent(); tabRect.sizeDelta = new Vector2(x, y); return tabRect; } public static RectTransform CreateTab(string name, RectTransform parent, float x, float y) { if (!InMainMenu()) { Core.Logger.Warning("Tried Creating UI outside Main Menu, Aborting."); return null; } var tabObj = new GameObject(name, typeof(RectTransform)); tabObj.transform.SetParent(parent, false); tabObj.layer = LayerMask.NameToLayer("UI"); var tabRect = tabObj.GetComponent(); tabRect.sizeDelta = new Vector2(x, y); return tabRect; } public static RectTransform CreateButton(string name, RectTransform parent, string buttonText, UnityAction callback) { if (!InMainMenu()) { Core.Logger.Warning("Tried Creating UI outside Main Menu, Aborting."); return null; } var newButton = UnityEngine.Object.Instantiate(GameObject.Find(BUTTON_PATH), parent); newButton.name = name; var buttonComp = newButton.GetComponent(); buttonComp.onClick = new UnityEngine.UI.Button.ButtonClickedEvent(); if (callback != null) buttonComp.onClick.AddListener(callback); var selectedText = newButton.transform.Find("Selected Text").GetComponent(); selectedText.text = $"[ {buttonText} ] "; var unselectedText = newButton.transform.Find("Unselected Text").GetComponent(); unselectedText.text = buttonText; newButton.AddComponent(); return newButton.GetComponent(); } public static RectTransform CreateText(string name, RectTransform parent, string text, Color color, out TextMeshProUGUI textMesh, int fontSize = 14) { if (!InMainMenu()) { Core.Logger.Warning("Tried Creating UI outside Main Menu, Aborting."); textMesh = null; return null; } var newText = UnityEngine.Object.Instantiate(GameObject.Find(BUTTON_PATH + "/Unselected Text"), parent); newText.name = name; UnityEngine.Object.DestroyImmediate(newText.GetComponent()); var textComp = newText.GetComponent(); textComp.text = text; if(color != Color.yellow) textComp.color = color; textComp.fontSize = fontSize; textMesh = textComp; newText.AddComponent(); return newText.GetComponent(); } public static RectTransform CreateWindow(string name, RectTransform parent, string title, out TextMeshProUGUI titleText, float width, UnityAction onClose) { if (!InMainMenu()) { Core.Logger.Warning("Tried Creating UI outside Main Menu, Aborting."); titleText = null; return null; } var newWindow = UnityEngine.Object.Instantiate(GameObject.Find(OPTIONS_PATH), parent); newWindow.name = name; for (int i = 0; i < newWindow.transform.childCount; i++) { var child = newWindow.transform.GetChild(i); if(child.name != "Header") { UnityEngine.Object.Destroy(child.gameObject); } } var text = newWindow.transform.GetChild(0).GetChild(0).GetComponent(); text.text = title; titleText = text; var closeButton = newWindow.transform.GetChild(0).GetChild(1).GetChild(0).GetComponent(); closeButton.onClick = new UnityEngine.UI.Button.ButtonClickedEvent(); if(onClose != null) closeButton.onClick.AddListener(onClose); else closeButton.gameObject.SetActive(false); var headerRect = newWindow.transform.GetChild(0).GetComponent(); headerRect.sizeDelta = new Vector2(width, headerRect.sizeDelta.y); var closeContainer = headerRect.GetChild(1).GetComponent(); closeContainer.anchorMin = new Vector2(1, 0.5f); closeContainer.anchorMax = new Vector2(1, 0.5f); closeContainer.pivot = new Vector2(1, 0.5f); closeContainer.anchoredPosition = new Vector2(10f, 10f); var buttonRect = closeContainer.GetChild(0).GetComponent(); buttonRect.anchorMin = new Vector2(0.5f, 0.5f); buttonRect.anchorMax = new Vector2(0.5f, 0.5f); buttonRect.pivot = new Vector2(0.5f, 0.5f); buttonRect.anchoredPosition = Vector2.zero; var windowRect = newWindow.GetComponent(); if (newWindow.activeSelf == false) newWindow.SetActive(true); newWindow.AddComponent(); return windowRect; } public static RectTransform CreateDivider(string name, RectTransform parent, Color color) { if (!InMainMenu()) { Core.Logger.Warning("Tried Creating UI outside Main Menu, Aborting."); return null; } var newDivider = UnityEngine.Object.Instantiate(GameObject.Find(DIVIDER_PATH), parent); newDivider.name = name; var textComp = newDivider.GetComponent(); StringBuilder stringBuilder = new StringBuilder(); float parentWidth = parent.sizeDelta.x; int dashCount = Mathf.FloorToInt(parentWidth / 10f); for (int i = 0; i < dashCount; i++) { stringBuilder.Append("-"); } textComp.text = stringBuilder.ToString(); textComp.color = color; var rect = newDivider.GetComponent(); rect.anchorMin = new Vector2(0f, rect.anchorMin.y); rect.anchorMax = new Vector2(1f, rect.anchorMax.y); rect.offsetMin = new Vector2(0f, rect.offsetMin.y); rect.offsetMax = new Vector2(0f, rect.offsetMax.y); newDivider.AddComponent(); return rect; } public static RectTransform CreateVerticalLayoutArea(string name, RectTransform parent, float spacing = 8f, RectOffset padding = null, TextAnchor alignment = TextAnchor.MiddleCenter, bool controlChildSize = true, bool forceExpand = false) { if (!InMainMenu()) { Core.Logger.Warning("Tried Creating UI outside Main Menu, Aborting."); return null; } var layoutObj = new GameObject(name, typeof(RectTransform)); layoutObj.transform.SetParent(parent, false); layoutObj.layer = LayerMask.NameToLayer("UI"); var rect = layoutObj.GetComponent(); rect.sizeDelta = Vector2.zero; var layout = layoutObj.AddComponent(); layout.childAlignment = alignment; layout.spacing = spacing; layout.padding = padding ?? new RectOffset(0, 0, 0, 0); layout.childControlWidth = controlChildSize; layout.childControlHeight = controlChildSize; layout.childForceExpandWidth = forceExpand; layout.childForceExpandHeight = forceExpand; var fitter = layoutObj.AddComponent(); fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize; layoutObj.AddComponent(); return rect; } public static RectTransform CreateHorizontalLayoutArea(string name, RectTransform parent, float spacing = 8f, RectOffset padding = null, TextAnchor alignment = TextAnchor.MiddleCenter, bool controlChildSize = true, bool forceExpand = false) { if (!InMainMenu()) { Core.Logger.Warning("Tried Creating UI outside Main Menu, Aborting."); return null; } var layoutObj = new GameObject(name, typeof(RectTransform)); layoutObj.transform.SetParent(parent, false); layoutObj.layer = LayerMask.NameToLayer("UI"); var rect = layoutObj.GetComponent(); rect.sizeDelta = Vector2.zero; var layout = layoutObj.AddComponent(); layout.childAlignment = alignment; layout.spacing = spacing; layout.padding = padding ?? new RectOffset(0, 0, 0, 0); layout.childControlWidth = controlChildSize; layout.childControlHeight = controlChildSize; layout.childForceExpandWidth = forceExpand; layout.childForceExpandHeight = forceExpand; var fitter = layoutObj.AddComponent(); fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize; layoutObj.AddComponent(); return rect; } public static RectTransform CreateSlider(string name, RectTransform parent, string sliderText, float maxValue, float minValue, float value, UnityAction onValueChanged) { if (!InMainMenu()) { Core.Logger.Warning("Tried Creating UI outside Main Menu, Aborting."); return null; } var newSlider = UnityEngine.Object.Instantiate(GameObject.Find(SLIDER_PATH), parent); newSlider.name = name; UnityEngine.Object.Destroy(newSlider.GetComponent()); newSlider.transform.GetChild(0).GetComponent().text = sliderText; var sliderComp = newSlider.transform.GetChild(2).GetComponent(); sliderComp.minValue = minValue; sliderComp.maxValue = maxValue; sliderComp.value = value; sliderComp.onValueChanged = new UnityEngine.UI.Slider.SliderEvent(); sliderComp.onValueChanged.AddListener(onValueChanged); var rectComp = newSlider.GetComponent(); newSlider.AddComponent(); return rectComp; } public static RectTransform CreateToggle(string name, RectTransform parent, string toggleText, bool value, UnityAction onValueChanged) { if (!InMainMenu()) { Core.Logger.Warning("Tried Creating UI outside Main Menu, Aborting."); return null; } var rootToggle = CreateHorizontalLayoutArea(name, parent, 15, null, TextAnchor.MiddleLeft, false, true); var toggleContainer = new GameObject("ToggleContainer", typeof(RectTransform)); toggleContainer.transform.SetParent(rootToggle.transform, false); toggleContainer.layer = LayerMask.NameToLayer("UI"); var toggleContainerRect = toggleContainer.GetComponent(); toggleContainerRect.sizeDelta = new Vector2(40f, 40f); var toggleShadow = new GameObject("ToggleShadow", typeof(RectTransform)); toggleShadow.transform.SetParent(toggleContainer.transform, false); toggleShadow.layer = LayerMask.NameToLayer("UI"); var toggleShadowRect = toggleShadow.GetComponent(); toggleShadowRect.sizeDelta = new Vector2(40f, 40f); var toggleShadowImage = toggleShadow.AddComponent(); toggleShadowImage.color = Color.black; var toggleGraphic = new GameObject("ToggleGraphic", typeof(RectTransform)); toggleGraphic.transform.SetParent(toggleShadow.transform, false); toggleGraphic.layer = LayerMask.NameToLayer("UI"); var toggleGraphicRect = toggleGraphic.GetComponent(); toggleGraphicRect.sizeDelta = new Vector2(30f, 30f); var toggleGraphicImage = toggleGraphic.AddComponent(); toggleGraphicImage.color = Color.yellow; var toggleComp = toggleContainer.AddComponent(); toggleComp.transition = Selectable.Transition.None; toggleComp.targetGraphic = toggleShadowImage; toggleComp.graphic = toggleGraphicImage; toggleComp.isOn = value; toggleComp.onValueChanged.AddListener(onValueChanged); CreateText("ToggleText", rootToggle, toggleText, Color.yellow, out TextMeshProUGUI text, 28); text.alignment = TextAlignmentOptions.BaselineLeft; return rootToggle; } public static RectTransform CreateVerticalScrollView(string name, RectTransform parent, float width, float height, out RectTransform contentRect, float contentPadding = 8f) { if (!InMainMenu()) { Core.Logger.Warning("Tried Creating UI outside Main Menu, Aborting."); contentRect = null; return null; } // Root ScrollView object var scrollViewObj = new GameObject(name, typeof(RectTransform), typeof(ScrollRect), typeof(Image)); scrollViewObj.transform.SetParent(parent, false); scrollViewObj.layer = LayerMask.NameToLayer("UI"); var scrollViewRect = scrollViewObj.GetComponent(); scrollViewRect.sizeDelta = new Vector2(width, height); // Make background invisible var scrollViewImage = scrollViewObj.GetComponent(); scrollViewImage.color = Color.clear; // Viewport var viewportObj = new GameObject("Viewport", typeof(RectTransform), typeof(UnityEngine.UI.Mask), typeof(Image)); viewportObj.transform.SetParent(scrollViewObj.transform, false); viewportObj.layer = LayerMask.NameToLayer("UI"); var viewportRect = viewportObj.GetComponent(); viewportRect.anchorMin = Vector2.zero; viewportRect.anchorMax = Vector2.one; viewportRect.offsetMin = Vector2.zero; viewportRect.offsetMax = Vector2.zero; var viewportImage = viewportObj.GetComponent(); viewportImage.color = Color.clear; var mask = viewportObj.GetComponent(); mask.showMaskGraphic = false; // Content container var contentObj = new GameObject("Content", typeof(RectTransform), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter)); contentObj.transform.SetParent(viewportObj.transform, false); contentObj.layer = LayerMask.NameToLayer("UI"); var contentRectComp = contentObj.GetComponent(); contentRectComp.anchorMin = new Vector2(0, 1); contentRectComp.anchorMax = new Vector2(1, 1); contentRectComp.pivot = new Vector2(0.5f, 1); contentRectComp.anchoredPosition = Vector2.zero; contentRectComp.sizeDelta = new Vector2(0, 0); var layout = contentObj.GetComponent(); layout.childAlignment = TextAnchor.UpperCenter; layout.spacing = contentPadding; layout.childForceExpandHeight = false; layout.childForceExpandWidth = true; var fitter = contentObj.GetComponent(); fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; fitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; // ScrollRect setup var scrollRect = scrollViewObj.GetComponent(); scrollRect.content = contentRectComp; scrollRect.viewport = viewportRect; scrollRect.horizontal = false; scrollRect.vertical = true; scrollRect.verticalScrollbarVisibility = ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport; // Scrollbar var scrollbarObj = new GameObject("Scrollbar", typeof(RectTransform), typeof(Scrollbar), typeof(Image)); scrollbarObj.transform.SetParent(scrollViewObj.transform, false); scrollbarObj.layer = LayerMask.NameToLayer("UI"); var scrollbarRect = scrollbarObj.GetComponent(); scrollbarRect.anchorMin = new Vector2(1, 0); scrollbarRect.anchorMax = new Vector2(1, 1); scrollbarRect.pivot = new Vector2(1, 1); scrollbarRect.sizeDelta = new Vector2(20f, 0); scrollbarRect.anchoredPosition = Vector2.zero; var scrollbarImage = scrollbarObj.GetComponent(); scrollbarImage.color = Color.yellow; var scrollbar = scrollbarObj.GetComponent(); scrollbar.direction = Scrollbar.Direction.BottomToTop; scrollRect.verticalScrollbar = scrollbar; scrollViewObj.AddComponent(); contentRect = contentRectComp; return scrollViewRect; } static bool InMainMenu() { return SceneManager.GetActiveScene().buildIndex == 0; } } }