// Add a new drop-down list item with the specified values. private ColorDropdownItem AddItem(OptionData data, bool selected, ColorDropdownItem itemTemplate, List <ColorDropdownItem> items) { // Add a new item to the dropdown. ColorDropdownItem item = CreateItem(itemTemplate); item.rectTransform.SetParent(itemTemplate.rectTransform.parent, false); item.gameObject.SetActive(true); item.gameObject.name = "Item " + items.Count + (data.text != null ? ": " + data.text : ""); if (item.toggle != null) { item.toggle.isOn = false; } // Set the item's data if (item.text) { item.text.text = data.text; } if (item.image) { item.image.sprite = data.image; item.image.enabled = (item.image.sprite != null); } items.Add(item); return(item); }
protected virtual void DestroyItem(ColorDropdownItem item) { // No action needed since destroying the dropdown list destroys all contained items as well. }
// 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 contains dropdowns. public void Show() { if (!IsActive() || !IsInteractable() || m_Dropdown != null) { return; } if (!validTemplate) { SetupTemplate(); if (!validTemplate) { return; } } // Get root Canvas. var list = ListPool <Canvas> .Get(); gameObject.GetComponentsInParent(false, list); if (list.Count == 0) { return; } Canvas rootCanvas = list[0]; ListPool <Canvas> .Release(list); m_Template.gameObject.SetActive(true); // 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. ColorDropdownItem itemTemplate = m_Dropdown.GetComponentInChildren <ColorDropdownItem>(); 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; ColorDropdownItem selectedItem = null; for (int i = 0; i < options.Count; ++i) { OptionData data = options[i]; ColorDropdownItem 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(); selectedItem = item; } // 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] || 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); if (selectedItem != null) { ScrollRect scr = m_Dropdown.GetComponent <ScrollRect>(); if (scr != null) { scr.content.localPosition = scr.GetSnapToPositionToBringChildIntoView(selectedItem.rectTransform); } } SimplexCalc.instance?.triggerRebuild(); m_Blocker = CreateBlocker(rootCanvas); }
protected virtual ColorDropdownItem CreateItem(ColorDropdownItem itemTemplate) { return((ColorDropdownItem)Instantiate(itemTemplate)); }
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 <Toggle>(); 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; } ColorDropdownItem item = itemToggle.gameObject.AddComponent <ColorDropdownItem>(); item.text = m_ItemText; item.image = m_ItemImage; item.toggle = itemToggle; item.rectTransform = (RectTransform)itemToggle.transform; Canvas popupCanvas = GetOrAddComponent <Canvas>(templateGo); popupCanvas.overrideSorting = true; popupCanvas.sortingOrder = 30000; GetOrAddComponent <GraphicRaycaster>(templateGo); GetOrAddComponent <CanvasGroup>(templateGo); templateGo.SetActive(false); validTemplate = true; }