From c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78 Mon Sep 17 00:00:00 2001 From: Andrew Lee Date: Sun, 19 Apr 2020 17:19:32 -0400 Subject: Inital commit --- .../Scripts/Runtime/TMP_Dropdown.cs | 1059 ++++++++++++++++++++ 1 file changed, 1059 insertions(+) create mode 100644 Library/PackageCache/com.unity.textmeshpro@2.0.1/Scripts/Runtime/TMP_Dropdown.cs (limited to 'Library/PackageCache/com.unity.textmeshpro@2.0.1/Scripts/Runtime/TMP_Dropdown.cs') diff --git a/Library/PackageCache/com.unity.textmeshpro@2.0.1/Scripts/Runtime/TMP_Dropdown.cs b/Library/PackageCache/com.unity.textmeshpro@2.0.1/Scripts/Runtime/TMP_Dropdown.cs new file mode 100644 index 0000000..6424a5a --- /dev/null +++ b/Library/PackageCache/com.unity.textmeshpro@2.0.1/Scripts/Runtime/TMP_Dropdown.cs @@ -0,0 +1,1059 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.Events; +using UnityEngine.EventSystems; +using UnityEngine.UI.CoroutineTween; + +namespace TMPro +{ + [AddComponentMenu("UI/Dropdown - TextMeshPro", 35)] + [RequireComponent(typeof(RectTransform))] + /// + /// A standard dropdown that presents a list of options when clicked, of which one can be chosen. + /// + /// + /// The dropdown component is a Selectable. When an option is chosen, the label and/or image of the control changes to show the chosen option. + /// + /// When a dropdown event occurs a callback is sent to any registered listeners of onValueChanged. + /// + public class TMP_Dropdown : Selectable, IPointerClickHandler, ISubmitHandler, ICancelHandler + { + protected internal class DropdownItem : MonoBehaviour, IPointerEnterHandler, ICancelHandler + { + [SerializeField] + private TMP_Text m_Text; + [SerializeField] + private Image m_Image; + [SerializeField] + private RectTransform m_RectTransform; + [SerializeField] + private Toggle m_Toggle; + + public TMP_Text text { get { return m_Text; } set { m_Text = value; } } + public Image image { get { return m_Image; } set { m_Image = value; } } + public RectTransform rectTransform { get { return m_RectTransform; } set { m_RectTransform = value; } } + public Toggle toggle { get { return m_Toggle; } set { m_Toggle = value; } } + + public virtual void OnPointerEnter(PointerEventData eventData) + { + EventSystem.current.SetSelectedGameObject(gameObject); + } + + public virtual void OnCancel(BaseEventData eventData) + { + TMP_Dropdown dropdown = GetComponentInParent(); + if (dropdown) + dropdown.Hide(); + } + } + + [Serializable] + /// + /// Class to store the text and/or image of a single option in the dropdown list. + /// + public class OptionData + { + [SerializeField] + private string m_Text; + [SerializeField] + private Sprite m_Image; + + /// + /// The text associated with the option. + /// + public string text { get { return m_Text; } set { m_Text = value; } } + + /// + /// The image associated with the option. + /// + public Sprite image { get { return m_Image; } set { m_Image = value; } } + + public OptionData() { } + + public OptionData(string text) + { + this.text = text; + } + + public OptionData(Sprite image) + { + this.image = image; + } + + /// + /// Create an object representing a single option for the dropdown list. + /// + /// Optional text for the option. + /// Optional image for the option. + public OptionData(string text, Sprite image) + { + this.text = text; + this.image = image; + } + } + + [Serializable] + /// + /// Class used internally to store the list of options for the dropdown list. + /// + /// + /// The usage of this class is not exposed in the runtime API. It's only relevant for the PropertyDrawer drawing the list of options. + /// + public class OptionDataList + { + [SerializeField] + private List m_Options; + + /// + /// The list of options for the dropdown list. + /// + public List options { get { return m_Options; } set { m_Options = value; } } + + + public OptionDataList() + { + options = new List(); + } + } + + [Serializable] + /// + /// UnityEvent callback for when a dropdown current option is changed. + /// + public class DropdownEvent : UnityEvent { } + + // Template used to create the dropdown. + [SerializeField] + private RectTransform m_Template; + + /// + /// The Rect Transform of the template for the dropdown list. + /// + public RectTransform template { get { return m_Template; } set { m_Template = value; RefreshShownValue(); } } + + // Text to be used as a caption for the current value. It's not required, but it's kept here for convenience. + [SerializeField] + private TMP_Text m_CaptionText; + + /// + /// The Text component to hold the text of the currently selected option. + /// + public TMP_Text captionText { get { return m_CaptionText; } set { m_CaptionText = value; RefreshShownValue(); } } + + [SerializeField] + private Image m_CaptionImage; + + /// + /// The Image component to hold the image of the currently selected option. + /// + public Image captionImage { get { return m_CaptionImage; } set { m_CaptionImage = value; RefreshShownValue(); } } + + [Space] + + [SerializeField] + private TMP_Text m_ItemText; + + /// + /// The Text component to hold the text of the item. + /// + public TMP_Text itemText { get { return m_ItemText; } set { m_ItemText = value; RefreshShownValue(); } } + + [SerializeField] + private Image m_ItemImage; + + /// + /// The Image component to hold the image of the item + /// + public Image itemImage { get { return m_ItemImage; } set { m_ItemImage = value; RefreshShownValue(); } } + + [Space] + + [SerializeField] + private int m_Value; + + [Space] + + // Items that will be visible when the dropdown is shown. + // We box this into its own class so we can use a Property Drawer for it. + [SerializeField] + private OptionDataList m_Options = new OptionDataList(); + + /// + /// The list of possible options. A text string and an image can be specified for each option. + /// + /// + /// This is the list of options within the Dropdown. Each option contains Text and/or image data that you can specify using UI.Dropdown.OptionData before adding to the Dropdown list. + /// This also unlocks the ability to edit the Dropdown, including the insertion, removal, and finding of options, as well as other useful tools + /// + /// /// + /// + /// //Create a new Dropdown GameObject by going to the Hierarchy and clicking Create>UI>Dropdown - TextMeshPro. Attach this script to the Dropdown GameObject. + /// + /// using UnityEngine; + /// using UnityEngine.UI; + /// using System.Collections.Generic; + /// using TMPro; + /// + /// public class Example : MonoBehaviour + /// { + /// //Use these for adding options to the Dropdown List + /// TMP_Dropdown.OptionData m_NewData, m_NewData2; + /// //The list of messages for the Dropdown + /// List m_Messages = new List(); + /// + /// + /// //This is the Dropdown + /// TMP_Dropdown m_Dropdown; + /// string m_MyString; + /// int m_Index; + /// + /// void Start() + /// { + /// //Fetch the Dropdown GameObject the script is attached to + /// m_Dropdown = GetComponent(); + /// //Clear the old options of the Dropdown menu + /// m_Dropdown.ClearOptions(); + /// + /// //Create a new option for the Dropdown menu which reads "Option 1" and add to messages List + /// m_NewData = new TMP_Dropdown.OptionData(); + /// m_NewData.text = "Option 1"; + /// m_Messages.Add(m_NewData); + /// + /// //Create a new option for the Dropdown menu which reads "Option 2" and add to messages List + /// m_NewData2 = new TMP_Dropdown.OptionData(); + /// m_NewData2.text = "Option 2"; + /// m_Messages.Add(m_NewData2); + /// + /// //Take each entry in the message List + /// foreach (TMP_Dropdown.OptionData message in m_Messages) + /// { + /// //Add each entry to the Dropdown + /// m_Dropdown.options.Add(message); + /// //Make the index equal to the total number of entries + /// m_Index = m_Messages.Count - 1; + /// } + /// } + /// + /// //This OnGUI function is used here for a quick demonstration. See the [[wiki:UISystem|UI Section]] for more information about setting up your own UI. + /// void OnGUI() + /// { + /// //TextField for user to type new entry to add to Dropdown + /// m_MyString = GUI.TextField(new Rect(0, 40, 100, 40), m_MyString); + /// + /// //Press the "Add" Button to add a new entry to the Dropdown + /// if (GUI.Button(new Rect(0, 0, 100, 40), "Add")) + /// { + /// //Make the index the last number of entries + /// m_Index = m_Messages.Count; + /// //Create a temporary option + /// TMP_Dropdown.OptionData temp = new TMP_Dropdown.OptionData(); + /// //Make the option the data from the TextField + /// temp.text = m_MyString; + /// + /// //Update the messages list with the TextField data + /// m_Messages.Add(temp); + /// + /// //Add the Textfield data to the Dropdown + /// m_Dropdown.options.Insert(m_Index, temp); + /// } + /// + /// //Press the "Remove" button to delete the selected option + /// if (GUI.Button(new Rect(110, 0, 100, 40), "Remove")) + /// { + /// //Remove the current selected item from the Dropdown from the messages List + /// m_Messages.RemoveAt(m_Dropdown.value); + /// //Remove the current selection from the Dropdown + /// m_Dropdown.options.RemoveAt(m_Dropdown.value); + /// } + /// } + /// } + /// + /// + public List options + { + get { return m_Options.options; } + set { m_Options.options = value; RefreshShownValue(); } + } + + [Space] + + // Notification triggered when the dropdown changes. + [SerializeField] + private DropdownEvent m_OnValueChanged = new DropdownEvent(); + + /// + /// A UnityEvent that is invoked when a user has clicked one of the options in the dropdown list. + /// + /// + /// Use this to detect when a user selects one or more options in the Dropdown. Add a listener to perform an action when this UnityEvent detects a selection by the user. See https://unity3d.com/learn/tutorials/topics/scripting/delegates for more information on delegates. + /// + /// + /// + /// //Create a new Dropdown GameObject by going to the Hierarchy and clicking Create>UI>Dropdown - TextMeshPro. Attach this script to the Dropdown GameObject. + /// //Set your own Text in the Inspector window + /// + /// using UnityEngine; + /// using UnityEngine.UI; + /// using TMPro; + /// + /// public class Example : MonoBehaviour + /// { + /// TMP_Dropdown m_Dropdown; + /// public Text m_Text; + /// + /// void Start() + /// { + /// //Fetch the Dropdown GameObject + /// m_Dropdown = GetComponent(); + /// //Add listener for when the value of the Dropdown changes, to take action + /// m_Dropdown.onValueChanged.AddListener(delegate { + /// DropdownValueChanged(m_Dropdown); + /// }); + /// + /// //Initialize the Text to say the first value of the Dropdown + /// m_Text.text = "First Value : " + m_Dropdown.value; + /// } + /// + /// //Output the new value of the Dropdown into Text + /// void DropdownValueChanged(TMP_Dropdown change) + /// { + /// m_Text.text = "New Value : " + change.value; + /// } + /// } + /// + /// + public DropdownEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } } + + private GameObject m_Dropdown; + private GameObject m_Blocker; + private List m_Items = new List(); + private TweenRunner m_AlphaTweenRunner; + private bool validTemplate = false; + + private static OptionData s_NoOptionData = new OptionData(); + + /// + /// The Value is the index number of the current selection in the Dropdown. 0 is the first option in the Dropdown, 1 is the second, and so on. + /// + /// + /// + /// //Create a new Dropdown GameObject by going to the Hierarchy and clicking Create>UI>Dropdown - TextMeshPro. Attach this script to the Dropdown GameObject. + /// //Set your own Text in the Inspector window + /// + /// using UnityEngine; + /// using UnityEngine.UI; + /// using TMPro; + /// + /// public class Example : MonoBehaviour + /// { + /// //Attach this script to a Dropdown GameObject + /// TMP_Dropdown m_Dropdown; + /// //This is the string that stores the current selection m_Text of the Dropdown + /// string m_Message; + /// //This Text outputs the current selection to the screen + /// public Text m_Text; + /// //This is the index value of the Dropdown + /// int m_DropdownValue; + /// + /// void Start() + /// { + /// //Fetch the DropDown component from the GameObject + /// m_Dropdown = GetComponent(); + /// //Output the first Dropdown index value + /// Debug.Log("Starting Dropdown Value : " + m_Dropdown.value); + /// } + /// + /// void Update() + /// { + /// //Keep the current index of the Dropdown in a variable + /// m_DropdownValue = m_Dropdown.value; + /// //Change the message to say the name of the current Dropdown selection using the value + /// m_Message = m_Dropdown.options[m_DropdownValue].text; + /// //Change the on screen Text to reflect the current Dropdown selection + /// m_Text.text = m_Message; + /// } + /// } + /// + /// + public int value + { + get + { + return m_Value; + } + set + { + SetValue(value); + } + } + + /// + /// Set index number of the current selection in the Dropdown without invoking onValueChanged callback. + /// + /// The new index for the current selection. + public void SetValueWithoutNotify(int input) + { + SetValue(input, false); + } + + void SetValue(int value, bool sendCallback = true) + { + if (Application.isPlaying && (value == m_Value || options.Count == 0)) + return; + + m_Value = Mathf.Clamp(value, 0, options.Count - 1); + RefreshShownValue(); + + if (sendCallback) + { + // Notify all listeners + UISystemProfilerApi.AddMarker("Dropdown.value", this); + m_OnValueChanged.Invoke(m_Value); + } + } + + public bool IsExpanded { get { return m_Dropdown != null; } } + + protected TMP_Dropdown() { } + + protected override void Awake() + { + #if UNITY_EDITOR + if (!Application.isPlaying) + return; + #endif + + m_AlphaTweenRunner = new TweenRunner(); + m_AlphaTweenRunner.Init(this); + + if (m_CaptionImage) + m_CaptionImage.enabled = (m_CaptionImage.sprite != null); + + if (m_Template) + m_Template.gameObject.SetActive(false); + } + + protected override void Start() + { + base.Start(); + + RefreshShownValue(); + } + + #if UNITY_EDITOR + protected override void OnValidate() + { + base.OnValidate(); + + if (!IsActive()) + return; + + RefreshShownValue(); + } + #endif + + protected override void OnDisable() + { + //Destroy dropdown and blocker in case user deactivates the dropdown when they click an option (case 935649) + ImmediateDestroyDropdownList(); + + if (m_Blocker != null) + DestroyBlocker(m_Blocker); + m_Blocker = null; + } + + /// + /// Refreshes the text and image (if available) of the currently selected option. + /// + /// + /// If you have modified the list of options, you should call this method afterwards to ensure that the visual state of the dropdown corresponds to the updated options. + /// + public void RefreshShownValue() + { + OptionData data = s_NoOptionData; + + if (options.Count > 0) + data = options[Mathf.Clamp(m_Value, 0, options.Count - 1)]; + + if (m_CaptionText) + { + if (data != null && data.text != null) + m_CaptionText.text = data.text; + else + m_CaptionText.text = ""; + } + + if (m_CaptionImage) + { + if (data != null) + m_CaptionImage.sprite = data.image; + else + m_CaptionImage.sprite = null; + m_CaptionImage.enabled = (m_CaptionImage.sprite != null); + } + } + + /// + /// Add multiple options to the options of the Dropdown based on a list of OptionData objects. + /// + /// The list of OptionData to add. + /// /// + /// See AddOptions(List options) for code example of usages. + /// + public void AddOptions(List options) + { + this.options.AddRange(options); + RefreshShownValue(); + } + + /// + /// Add multiple text-only options to the options of the Dropdown based on a list of strings. + /// + /// + /// Add a List of string messages to the Dropdown. The Dropdown shows each member of the list as a separate option. + /// + /// The list of text strings to add. + /// + /// + /// //Create a new Dropdown GameObject by going to the Hierarchy and clicking Create>UI>Dropdown - TextMeshPro. Attach this script to the Dropdown GameObject. + /// + /// using System.Collections.Generic; + /// using UnityEngine; + /// using UnityEngine.UI; + /// using TMPro; + /// + /// public class Example : MonoBehaviour + /// { + /// //Create a List of new Dropdown options + /// List m_DropOptions = new List { "Option 1", "Option 2"}; + /// //This is the Dropdown + /// TMP_Dropdown m_Dropdown; + /// + /// void Start() + /// { + /// //Fetch the Dropdown GameObject the script is attached to + /// m_Dropdown = GetComponent(); + /// //Clear the old options of the Dropdown menu + /// m_Dropdown.ClearOptions(); + /// //Add the options created in the List above + /// m_Dropdown.AddOptions(m_DropOptions); + /// } + /// } + /// + /// + public void AddOptions(List options) + { + for (int i = 0; i < options.Count; i++) + this.options.Add(new OptionData(options[i])); + + RefreshShownValue(); + } + + /// + /// Add multiple image-only options to the options of the Dropdown based on a list of Sprites. + /// + /// The list of Sprites to add. + /// + /// See AddOptions(List options) for code example of usages. + /// + public void AddOptions(List options) + { + for (int i = 0; i < options.Count; i++) + this.options.Add(new OptionData(options[i])); + + RefreshShownValue(); + } + + /// + /// Clear the list of options in the Dropdown. + /// + public void ClearOptions() + { + options.Clear(); + m_Value = 0; + RefreshShownValue(); + } + + private void SetupTemplate() + { + validTemplate = false; + + if (!m_Template) + { + Debug.LogError("The dropdown template is not assigned. The template needs to be assigned and must have a child GameObject with a Toggle component serving as the item.", this); + return; + } + + GameObject templateGo = m_Template.gameObject; + templateGo.SetActive(true); + Toggle itemToggle = m_Template.GetComponentInChildren(); + + validTemplate = true; + if (!itemToggle || itemToggle.transform == template) + { + validTemplate = false; + Debug.LogError("The dropdown template is not valid. The template must have a child GameObject with a Toggle component serving as the item.", template); + } + else if (!(itemToggle.transform.parent is RectTransform)) + { + validTemplate = false; + Debug.LogError("The dropdown template is not valid. The child GameObject with a Toggle component (the item) must have a RectTransform on its parent.", template); + } + else if (itemText != null && !itemText.transform.IsChildOf(itemToggle.transform)) + { + validTemplate = false; + Debug.LogError("The dropdown template is not valid. The Item Text must be on the item GameObject or children of it.", template); + } + else if (itemImage != null && !itemImage.transform.IsChildOf(itemToggle.transform)) + { + validTemplate = false; + Debug.LogError("The dropdown template is not valid. The Item Image must be on the item GameObject or children of it.", template); + } + + if (!validTemplate) + { + templateGo.SetActive(false); + return; + } + + DropdownItem item = itemToggle.gameObject.AddComponent(); + item.text = m_ItemText; + item.image = m_ItemImage; + item.toggle = itemToggle; + item.rectTransform = (RectTransform)itemToggle.transform; + + Canvas popupCanvas = GetOrAddComponent(templateGo); + popupCanvas.overrideSorting = true; + popupCanvas.sortingOrder = 30000; + + GetOrAddComponent(templateGo); + GetOrAddComponent(templateGo); + templateGo.SetActive(false); + + validTemplate = true; + } + + private static T GetOrAddComponent(GameObject go) where T : Component + { + T comp = go.GetComponent(); + if (!comp) + comp = go.AddComponent(); + return comp; + } + + /// + /// Handling for when the dropdown is initially 'clicked'. Typically shows the dropdown + /// + /// The associated event data. + public virtual void OnPointerClick(PointerEventData eventData) + { + Show(); + } + + /// + /// Handling for when the dropdown is selected and a submit event is processed. Typically shows the dropdown + /// + /// The associated event data. + public virtual void OnSubmit(BaseEventData eventData) + { + Show(); + } + + /// + /// This will hide the dropdown list. + /// + /// + /// Called by a BaseInputModule when a Cancel event occurs. + /// + /// The associated event data. + public virtual void OnCancel(BaseEventData eventData) + { + Hide(); + } + + /// + /// Show the dropdown. + /// + /// Plan for dropdown scrolling to ensure dropdown is contained within screen. + /// + /// We assume the Canvas is the screen that the dropdown must be kept inside. + /// This is always valid for screen space canvas modes. + /// For world space canvases we don't know how it's used, but it could be e.g. for an in-game monitor. + /// We consider it a fair constraint that the canvas must be big enough to contain dropdowns. + /// + public void Show() + { + if (!IsActive() || !IsInteractable() || m_Dropdown != null) + return; + + // Get root Canvas. + var list = TMP_ListPool.Get(); + gameObject.GetComponentsInParent(false, list); + if (list.Count == 0) + return; + + Canvas rootCanvas = list[list.Count - 1]; + for (int i = 0; i < list.Count; i++) + { + if (list[i].isRootCanvas) + { + rootCanvas = list[i]; + break; + } + } + + TMP_ListPool.Release(list); + + if (!validTemplate) + { + SetupTemplate(); + if (!validTemplate) + return; + } + + m_Template.gameObject.SetActive(true); + + // popupCanvas used to assume the root canvas had the default sorting Layer, next line fixes (case 958281 - [UI] Dropdown list does not copy the parent canvas layer when the panel is opened) + m_Template.GetComponent().sortingLayerID = rootCanvas.sortingLayerID; + + // Instantiate the drop-down template + m_Dropdown = CreateDropdownList(m_Template.gameObject); + m_Dropdown.name = "Dropdown List"; + m_Dropdown.SetActive(true); + + // Make drop-down RectTransform have same values as original. + RectTransform dropdownRectTransform = m_Dropdown.transform as RectTransform; + dropdownRectTransform.SetParent(m_Template.transform.parent, false); + + // Instantiate the drop-down list items + + // Find the dropdown item and disable it. + DropdownItem itemTemplate = m_Dropdown.GetComponentInChildren(); + + GameObject content = itemTemplate.rectTransform.parent.gameObject; + RectTransform contentRectTransform = content.transform as RectTransform; + itemTemplate.rectTransform.gameObject.SetActive(true); + + // Get the rects of the dropdown and item + Rect dropdownContentRect = contentRectTransform.rect; + Rect itemTemplateRect = itemTemplate.rectTransform.rect; + + // Calculate the visual offset between the item's edges and the background's edges + Vector2 offsetMin = itemTemplateRect.min - dropdownContentRect.min + (Vector2)itemTemplate.rectTransform.localPosition; + Vector2 offsetMax = itemTemplateRect.max - dropdownContentRect.max + (Vector2)itemTemplate.rectTransform.localPosition; + Vector2 itemSize = itemTemplateRect.size; + + m_Items.Clear(); + + Toggle prev = null; + for (int i = 0; i < options.Count; ++i) + { + OptionData data = options[i]; + DropdownItem item = AddItem(data, value == i, itemTemplate, m_Items); + if (item == null) + continue; + + // Automatically set up a toggle state change listener + item.toggle.isOn = value == i; + item.toggle.onValueChanged.AddListener(x => OnSelectItem(item.toggle)); + + // Select current option + if (item.toggle.isOn) + item.toggle.Select(); + + // Automatically set up explicit navigation + if (prev != null) + { + Navigation prevNav = prev.navigation; + Navigation toggleNav = item.toggle.navigation; + prevNav.mode = Navigation.Mode.Explicit; + toggleNav.mode = Navigation.Mode.Explicit; + + prevNav.selectOnDown = item.toggle; + prevNav.selectOnRight = item.toggle; + toggleNav.selectOnLeft = prev; + toggleNav.selectOnUp = prev; + + prev.navigation = prevNav; + item.toggle.navigation = toggleNav; + } + prev = item.toggle; + } + + // Reposition all items now that all of them have been added + Vector2 sizeDelta = contentRectTransform.sizeDelta; + sizeDelta.y = itemSize.y * m_Items.Count + offsetMin.y - offsetMax.y; + contentRectTransform.sizeDelta = sizeDelta; + + float extraSpace = dropdownRectTransform.rect.height - contentRectTransform.rect.height; + if (extraSpace > 0) + dropdownRectTransform.sizeDelta = new Vector2(dropdownRectTransform.sizeDelta.x, dropdownRectTransform.sizeDelta.y - extraSpace); + + // Invert anchoring and position if dropdown is partially or fully outside of canvas rect. + // Typically this will have the effect of placing the dropdown above the button instead of below, + // but it works as inversion regardless of initial setup. + Vector3[] corners = new Vector3[4]; + dropdownRectTransform.GetWorldCorners(corners); + + RectTransform rootCanvasRectTransform = rootCanvas.transform as RectTransform; + Rect rootCanvasRect = rootCanvasRectTransform.rect; + for (int axis = 0; axis < 2; axis++) + { + bool outside = false; + for (int i = 0; i < 4; i++) + { + Vector3 corner = rootCanvasRectTransform.InverseTransformPoint(corners[i]); + if ((corner[axis] < rootCanvasRect.min[axis] && !Mathf.Approximately(corner[axis], rootCanvasRect.min[axis])) || + (corner[axis] > rootCanvasRect.max[axis] && !Mathf.Approximately(corner[axis], rootCanvasRect.max[axis]))) + { + outside = true; + break; + } + } + if (outside) + RectTransformUtility.FlipLayoutOnAxis(dropdownRectTransform, axis, false, false); + } + + for (int i = 0; i < m_Items.Count; i++) + { + RectTransform itemRect = m_Items[i].rectTransform; + itemRect.anchorMin = new Vector2(itemRect.anchorMin.x, 0); + itemRect.anchorMax = new Vector2(itemRect.anchorMax.x, 0); + itemRect.anchoredPosition = new Vector2(itemRect.anchoredPosition.x, offsetMin.y + itemSize.y * (m_Items.Count - 1 - i) + itemSize.y * itemRect.pivot.y); + itemRect.sizeDelta = new Vector2(itemRect.sizeDelta.x, itemSize.y); + } + + // Fade in the popup + AlphaFadeList(0.15f, 0f, 1f); + + // Make drop-down template and item template inactive + m_Template.gameObject.SetActive(false); + itemTemplate.gameObject.SetActive(false); + + m_Blocker = CreateBlocker(rootCanvas); + } + + /// + /// Create a blocker that blocks clicks to other controls while the dropdown list is open. + /// + /// + /// Override this method to implement a different way to obtain a blocker GameObject. + /// + /// The root canvas the dropdown is under. + /// The created blocker object + protected virtual GameObject CreateBlocker(Canvas rootCanvas) + { + // Create blocker GameObject. + GameObject blocker = new GameObject("Blocker"); + + // Setup blocker RectTransform to cover entire root canvas area. + RectTransform blockerRect = blocker.AddComponent(); + blockerRect.SetParent(rootCanvas.transform, false); + blockerRect.anchorMin = Vector3.zero; + blockerRect.anchorMax = Vector3.one; + blockerRect.sizeDelta = Vector2.zero; + + // Make blocker be in separate canvas in same layer as dropdown and in layer just below it. + Canvas blockerCanvas = blocker.AddComponent(); + blockerCanvas.overrideSorting = true; + Canvas dropdownCanvas = m_Dropdown.GetComponent(); + blockerCanvas.sortingLayerID = dropdownCanvas.sortingLayerID; + blockerCanvas.sortingOrder = dropdownCanvas.sortingOrder - 1; + + // Add raycaster since it's needed to block. + blocker.AddComponent(); + + // Add image since it's needed to block, but make it clear. + Image blockerImage = blocker.AddComponent(); + blockerImage.color = Color.clear; + + // Add button since it's needed to block, and to close the dropdown when blocking area is clicked. + Button blockerButton = blocker.AddComponent