using System; using System.Collections; using System.Collections.Generic; using UnityEngine; [ExecuteInEditMode] [AddComponentMenu("NGUI/Interaction/Popup List")] public class UIPopupList : UIWidgetContainer { public enum Position { Auto, Above, Below } public enum OpenOn { ClickOrTap, RightClick, DoubleClick, Manual } public delegate void LegacyEvent(string val); public static UIPopupList current; private static GameObject mChild; private static float mFadeOutComplete; private const float animSpeed = 0.15f; public UIAtlas atlas; public UIFont bitmapFont; public Font trueTypeFont; public int fontSize = 16; public FontStyle fontStyle; public string backgroundSprite; public string highlightSprite; public Position position; public NGUIText.Alignment alignment = NGUIText.Alignment.Left; public List items = new List(); public List itemData = new List(); public Vector2 padding = new Vector3(4f, 4f); public Color textColor = Color.white; public Color backgroundColor = Color.white; public Color highlightColor = new Color(0.88235295f, 40f / 51f, 0.5882353f, 1f); public bool isAnimated = true; public bool isLocalized; public bool separatePanel = true; public OpenOn openOn; public List onChange = new List(); [HideInInspector] [SerializeField] protected string mSelectedItem; [HideInInspector] [SerializeField] protected UIPanel mPanel; [HideInInspector] [SerializeField] protected UISprite mBackground; [HideInInspector] [SerializeField] protected UISprite mHighlight; [HideInInspector] [SerializeField] protected UILabel mHighlightedLabel; [HideInInspector] [SerializeField] protected List mLabelList = new List(); [HideInInspector] [SerializeField] protected float mBgBorder; [NonSerialized] protected GameObject mSelection; [NonSerialized] protected int mOpenFrame; [HideInInspector] [SerializeField] private GameObject eventReceiver; [HideInInspector] [SerializeField] private string functionName = "OnSelectionChange"; [HideInInspector] [SerializeField] private float textScale; [HideInInspector] [SerializeField] private UIFont font; [HideInInspector] [SerializeField] private UILabel textLabel; private LegacyEvent mLegacyEvent; [NonSerialized] protected bool mExecuting; protected bool mUseDynamicFont; protected bool mTweening; public GameObject source; public UnityEngine.Object ambigiousFont { get { if (trueTypeFont != null) { return trueTypeFont; } if (bitmapFont != null) { return bitmapFont; } return font; } set { if (value is Font) { trueTypeFont = value as Font; bitmapFont = null; font = null; } else if (value is UIFont) { bitmapFont = value as UIFont; trueTypeFont = null; font = null; } } } [Obsolete("Use EventDelegate.Add(popup.onChange, YourCallback) instead, and UIPopupList.current.value to determine the state")] public LegacyEvent onSelectionChange { get { return mLegacyEvent; } set { mLegacyEvent = value; } } public static bool isOpen { get { if (current != null) { if (!(mChild != null)) { return mFadeOutComplete > Time.unscaledTime; } return true; } return false; } } public virtual string value { get { return mSelectedItem; } set { mSelectedItem = value; if (mSelectedItem != null && mSelectedItem != null) { TriggerCallbacks(); } } } public virtual object data { get { int num = items.IndexOf(mSelectedItem); if (num <= -1 || num >= itemData.Count) { return null; } return itemData[num]; } } public bool isColliderEnabled { get { Collider component = GetComponent(); if (component != null) { return component.enabled; } Collider2D component2 = GetComponent(); if (component2 != null) { return component2.enabled; } return false; } } [Obsolete("Use 'value' instead")] public string selection { get { return value; } set { this.value = value; } } private bool isValid { get { if (!(bitmapFont != null)) { return trueTypeFont != null; } return true; } } private int activeFontSize { get { if (!(trueTypeFont != null) && !(bitmapFont == null)) { return bitmapFont.defaultSize; } return fontSize; } } private float activeFontScale { get { if (!(trueTypeFont != null) && !(bitmapFont == null)) { return (float)fontSize / (float)bitmapFont.defaultSize; } return 1f; } } public virtual void Clear() { items.Clear(); itemData.Clear(); } public virtual void AddItem(string text) { items.Add(text); itemData.Add(null); } public virtual void AddItem(string text, object data) { items.Add(text); itemData.Add(data); } public virtual void RemoveItem(string text) { int num = items.IndexOf(text); if (num != -1) { items.RemoveAt(num); itemData.RemoveAt(num); } } public virtual void RemoveItemByData(object data) { int num = itemData.IndexOf(data); if (num != -1) { items.RemoveAt(num); itemData.RemoveAt(num); } } protected void TriggerCallbacks() { if (!mExecuting) { mExecuting = true; UIPopupList uIPopupList = current; current = this; if (mLegacyEvent != null) { mLegacyEvent(mSelectedItem); } if (EventDelegate.IsValid(onChange)) { EventDelegate.Execute(onChange); } else if (eventReceiver != null && !string.IsNullOrEmpty(functionName)) { eventReceiver.SendMessage(functionName, mSelectedItem, SendMessageOptions.DontRequireReceiver); } current = uIPopupList; mExecuting = false; } } protected virtual void OnEnable() { if (EventDelegate.IsValid(onChange)) { eventReceiver = null; functionName = null; } if (font != null) { if (font.isDynamic) { trueTypeFont = font.dynamicFont; fontStyle = font.dynamicFontStyle; mUseDynamicFont = true; } else if (bitmapFont == null) { bitmapFont = font; mUseDynamicFont = false; } font = null; } if (textScale != 0f) { fontSize = ((bitmapFont != null) ? Mathf.RoundToInt((float)bitmapFont.defaultSize * textScale) : 16); textScale = 0f; } if (trueTypeFont == null && bitmapFont != null && bitmapFont.isDynamic) { trueTypeFont = bitmapFont.dynamicFont; bitmapFont = null; } } protected virtual void OnValidate() { Font font = trueTypeFont; UIFont uIFont = bitmapFont; bitmapFont = null; trueTypeFont = null; if (font != null && (uIFont == null || !mUseDynamicFont)) { bitmapFont = null; trueTypeFont = font; mUseDynamicFont = true; } else if (uIFont != null) { if (uIFont.isDynamic) { trueTypeFont = uIFont.dynamicFont; fontStyle = uIFont.dynamicFontStyle; fontSize = uIFont.defaultSize; mUseDynamicFont = true; } else { bitmapFont = uIFont; mUseDynamicFont = false; } } else { trueTypeFont = font; mUseDynamicFont = true; } } protected virtual void Start() { if (textLabel != null) { EventDelegate.Add(onChange, textLabel.SetCurrentSelection); textLabel = null; } if (Application.isPlaying) { if (string.IsNullOrEmpty(mSelectedItem) && items.Count > 0) { mSelectedItem = items[0]; } if (!string.IsNullOrEmpty(mSelectedItem)) { TriggerCallbacks(); } } } protected virtual void OnLocalize() { if (isLocalized) { TriggerCallbacks(); } } protected virtual void Highlight(UILabel lbl, bool instant) { if (!(mHighlight != null)) { return; } mHighlightedLabel = lbl; if (mHighlight.GetAtlasSprite() == null) { return; } Vector3 highlightPosition = GetHighlightPosition(); if (!instant && isAnimated) { TweenPosition.Begin(mHighlight.gameObject, 0.1f, highlightPosition).method = UITweener.Method.EaseOut; if (!mTweening) { mTweening = true; StartCoroutine("UpdateTweenPosition"); } } else { mHighlight.cachedTransform.localPosition = highlightPosition; } } protected virtual Vector3 GetHighlightPosition() { if (mHighlightedLabel == null || mHighlight == null) { return Vector3.zero; } UISpriteData atlasSprite = mHighlight.GetAtlasSprite(); if (atlasSprite == null) { return Vector3.zero; } float pixelSize = atlas.pixelSize; float num = (float)atlasSprite.borderLeft * pixelSize; float y = (float)atlasSprite.borderTop * pixelSize; return mHighlightedLabel.cachedTransform.localPosition + new Vector3(0f - num, y, 1f); } protected virtual IEnumerator UpdateTweenPosition() { if (mHighlight != null && mHighlightedLabel != null) { TweenPosition tp = mHighlight.GetComponent(); while (tp != null && tp.enabled) { tp.to = GetHighlightPosition(); yield return null; } } mTweening = false; } protected virtual void OnItemHover(GameObject go, bool isOver) { if (isOver) { UILabel component = go.GetComponent(); Highlight(component, instant: false); } } protected virtual void OnItemPress(GameObject go, bool isPressed) { if (!isPressed) { return; } Select(go.GetComponent(), instant: true); UIEventListener component = go.GetComponent(); value = component.parameter as string; UIPlaySound[] components = GetComponents(); int i = 0; for (int num = components.Length; i < num; i++) { UIPlaySound uIPlaySound = components[i]; if (uIPlaySound.trigger == UIPlaySound.Trigger.OnClick) { NGUITools.PlaySound(uIPlaySound.audioClip, uIPlaySound.volume, 1f); } } CloseSelf(); } private void Select(UILabel lbl, bool instant) { Highlight(lbl, instant); } protected virtual void OnNavigate(KeyCode key) { if (!base.enabled || !(current == this)) { return; } int num = mLabelList.IndexOf(mHighlightedLabel); if (num == -1) { num = 0; } switch (key) { case KeyCode.UpArrow: if (num > 0) { Select(mLabelList[--num], instant: false); } break; case KeyCode.DownArrow: if (num + 1 < mLabelList.Count) { Select(mLabelList[++num], instant: false); } break; } } protected virtual void OnKey(KeyCode key) { if (base.enabled && current == this && (key == UICamera.current.cancelKey0 || key == UICamera.current.cancelKey1)) { OnSelect(isSelected: false); } } protected virtual void OnDisable() { CloseSelf(); } protected virtual void OnSelect(bool isSelected) { if (!isSelected) { CloseSelf(); } } public static void Close() { if (current != null) { current.CloseSelf(); current = null; } } public virtual void CloseSelf() { if (!(mChild != null) || !(current == this)) { return; } StopCoroutine("CloseIfUnselected"); mSelection = null; mLabelList.Clear(); if (isAnimated) { UIWidget[] componentsInChildren = mChild.GetComponentsInChildren(); int i = 0; for (int num = componentsInChildren.Length; i < num; i++) { UIWidget obj = componentsInChildren[i]; Color color = obj.color; color.a = 0f; TweenColor.Begin(obj.gameObject, 0.15f, color).method = UITweener.Method.EaseOut; } Collider[] componentsInChildren2 = mChild.GetComponentsInChildren(); int j = 0; for (int num2 = componentsInChildren2.Length; j < num2; j++) { componentsInChildren2[j].enabled = false; } UnityEngine.Object.Destroy(mChild, 0.15f); mFadeOutComplete = Time.unscaledTime + Mathf.Max(0.1f, 0.15f); } else { UnityEngine.Object.Destroy(mChild); mFadeOutComplete = Time.unscaledTime + 0.1f; } mBackground = null; mHighlight = null; mChild = null; current = null; } protected virtual void AnimateColor(UIWidget widget) { Color color = widget.color; widget.color = new Color(color.r, color.g, color.b, 0f); TweenColor.Begin(widget.gameObject, 0.15f, color).method = UITweener.Method.EaseOut; } protected virtual void AnimatePosition(UIWidget widget, bool placeAbove, float bottom) { Vector3 localPosition = widget.cachedTransform.localPosition; Vector3 localPosition2 = (placeAbove ? new Vector3(localPosition.x, bottom, localPosition.z) : new Vector3(localPosition.x, 0f, localPosition.z)); widget.cachedTransform.localPosition = localPosition2; TweenPosition.Begin(widget.gameObject, 0.15f, localPosition).method = UITweener.Method.EaseOut; } protected virtual void AnimateScale(UIWidget widget, bool placeAbove, float bottom) { GameObject go = widget.gameObject; Transform cachedTransform = widget.cachedTransform; float num = (float)activeFontSize * activeFontScale + mBgBorder * 2f; cachedTransform.localScale = new Vector3(1f, num / (float)widget.height, 1f); TweenScale.Begin(go, 0.15f, Vector3.one).method = UITweener.Method.EaseOut; if (placeAbove) { Vector3 localPosition = cachedTransform.localPosition; cachedTransform.localPosition = new Vector3(localPosition.x, localPosition.y - (float)widget.height + num, localPosition.z); TweenPosition.Begin(go, 0.15f, localPosition).method = UITweener.Method.EaseOut; } } private void Animate(UIWidget widget, bool placeAbove, float bottom) { AnimateColor(widget); AnimatePosition(widget, placeAbove, bottom); } protected virtual void OnClick() { if (mOpenFrame == Time.frameCount) { return; } if (mChild == null) { if (openOn != OpenOn.DoubleClick && openOn != OpenOn.Manual && (openOn != OpenOn.RightClick || UICamera.currentTouchID == -2)) { Show(); } } else if (mHighlightedLabel != null) { OnItemPress(mHighlightedLabel.gameObject, isPressed: true); } } protected virtual void OnDoubleClick() { if (openOn == OpenOn.DoubleClick) { Show(); } } private IEnumerator CloseIfUnselected() { do { yield return null; } while (!(UICamera.selectedObject != mSelection)); CloseSelf(); } public virtual void Show() { if (base.enabled && NGUITools.GetActive(base.gameObject) && mChild == null && atlas != null && isValid && items.Count > 0) { mLabelList.Clear(); StopCoroutine("CloseIfUnselected"); UICamera.selectedObject = UICamera.hoveredObject ?? base.gameObject; mSelection = UICamera.selectedObject; source = UICamera.selectedObject; if (source == null) { Debug.LogError("Popup list needs a source object..."); return; } mOpenFrame = Time.frameCount; if (mPanel == null) { mPanel = UIPanel.Find(base.transform); if (mPanel == null) { return; } } mChild = new GameObject("Drop-down List"); mChild.layer = base.gameObject.layer; if (separatePanel) { if (GetComponent() != null) { mChild.AddComponent().isKinematic = true; } else if (GetComponent() != null) { mChild.AddComponent().isKinematic = true; } mChild.AddComponent().depth = 1000000; } current = this; Transform transform = mChild.transform; transform.parent = mPanel.cachedTransform; Vector3 vector2; Vector3 vector3; Vector3 vector; if (openOn == OpenOn.Manual && mSelection != base.gameObject) { vector = UICamera.lastEventPosition; vector2 = mPanel.cachedTransform.InverseTransformPoint(mPanel.anchorCamera.ScreenToWorldPoint(vector)); vector3 = vector2; transform.localPosition = vector2; vector = transform.position; } else { Bounds bounds = NGUIMath.CalculateRelativeWidgetBounds(mPanel.cachedTransform, base.transform, considerInactive: false, considerChildren: false); vector2 = bounds.min; vector3 = bounds.max; transform.localPosition = vector2; vector = transform.position; } StartCoroutine("CloseIfUnselected"); transform.localRotation = Quaternion.identity; transform.localScale = Vector3.one; mBackground = NGUITools.AddSprite(mChild, atlas, backgroundSprite, (!separatePanel) ? NGUITools.CalculateNextDepth(mPanel.gameObject) : 0); mBackground.pivot = UIWidget.Pivot.TopLeft; mBackground.color = backgroundColor; Vector4 border = mBackground.border; mBgBorder = border.y; mBackground.cachedTransform.localPosition = new Vector3(0f, border.y, 0f); mHighlight = NGUITools.AddSprite(mChild, atlas, highlightSprite, mBackground.depth + 1); mHighlight.pivot = UIWidget.Pivot.TopLeft; mHighlight.color = highlightColor; UISpriteData atlasSprite = mHighlight.GetAtlasSprite(); if (atlasSprite == null) { return; } float num = atlasSprite.borderTop; float num2 = activeFontSize; float num3 = activeFontScale; float num4 = num2 * num3; float a = 0f; float num5 = 0f - padding.y; List list = new List(); if (!items.Contains(mSelectedItem)) { mSelectedItem = null; } int i = 0; for (int count = items.Count; i < count; i++) { string text = items[i]; UILabel uILabel = NGUITools.AddWidget(mChild, mBackground.depth + 2); uILabel.name = i.ToString(); uILabel.pivot = UIWidget.Pivot.TopLeft; uILabel.bitmapFont = bitmapFont; uILabel.trueTypeFont = trueTypeFont; uILabel.fontSize = fontSize; uILabel.fontStyle = fontStyle; uILabel.text = (isLocalized ? Localization.Get(text) : text); uILabel.color = textColor; uILabel.cachedTransform.localPosition = new Vector3(border.x + padding.x - uILabel.pivotOffset.x, num5, -1f); uILabel.overflowMethod = UILabel.Overflow.ResizeFreely; uILabel.alignment = alignment; list.Add(uILabel); num5 -= num4; num5 -= padding.y; a = Mathf.Max(a, uILabel.printedSize.x); UIEventListener uIEventListener = UIEventListener.Get(uILabel.gameObject); uIEventListener.onHover = OnItemHover; uIEventListener.onPress = OnItemPress; uIEventListener.parameter = text; if (mSelectedItem == text || (i == 0 && string.IsNullOrEmpty(mSelectedItem))) { Highlight(uILabel, instant: true); } mLabelList.Add(uILabel); } a = Mathf.Max(a, vector3.x - vector2.x - (border.x + padding.x) * 2f); float num6 = a; Vector3 vector4 = new Vector3(num6 * 0.5f, (0f - num4) * 0.5f, 0f); Vector3 vector5 = new Vector3(num6, num4 + padding.y, 1f); int j = 0; for (int count2 = list.Count; j < count2; j++) { UILabel uILabel2 = list[j]; NGUITools.AddWidgetCollider(uILabel2.gameObject); uILabel2.autoResizeBoxCollider = false; BoxCollider component = uILabel2.GetComponent(); if (component != null) { vector4.z = component.center.z; component.center = vector4; component.size = vector5; } else { BoxCollider2D component2 = uILabel2.GetComponent(); component2.offset = vector4; component2.size = vector5; } } int width = Mathf.RoundToInt(a); a += (border.x + padding.x) * 2f; num5 -= border.y; mBackground.width = Mathf.RoundToInt(a); mBackground.height = Mathf.RoundToInt(0f - num5 + border.y); int k = 0; for (int count3 = list.Count; k < count3; k++) { UILabel uILabel3 = list[k]; uILabel3.overflowMethod = UILabel.Overflow.ShrinkContent; uILabel3.width = width; } float num7 = 2f * atlas.pixelSize; float f = a - (border.x + padding.x) * 2f + (float)atlasSprite.borderLeft * num7; float f2 = num4 + num * num7; mHighlight.width = Mathf.RoundToInt(f); mHighlight.height = Mathf.RoundToInt(f2); bool flag = position == Position.Above; if (position == Position.Auto) { UICamera uICamera = UICamera.FindCameraForLayer(mSelection.layer); if (uICamera != null) { flag = uICamera.cachedCamera.WorldToViewportPoint(vector).y < 0.5f; } } if (isAnimated) { AnimateColor(mBackground); if (Time.timeScale == 0f || Time.timeScale >= 0.1f) { float bottom = num5 + num4; Animate(mHighlight, flag, bottom); int l = 0; for (int count4 = list.Count; l < count4; l++) { Animate(list[l], flag, bottom); } AnimateScale(mBackground, flag, bottom); } } if (flag) { vector2.y = vector3.y - border.y; vector3.y = vector2.y + (float)mBackground.height; vector3.x = vector2.x + (float)mBackground.width; transform.localPosition = new Vector3(vector2.x, vector3.y - border.y, vector2.z); } else { vector3.y = vector2.y + border.y; vector2.y = vector3.y - (float)mBackground.height; vector3.x = vector2.x + (float)mBackground.width; } Transform parent = mPanel.cachedTransform.parent; if (parent != null) { vector2 = mPanel.cachedTransform.TransformPoint(vector2); vector3 = mPanel.cachedTransform.TransformPoint(vector3); vector2 = parent.InverseTransformPoint(vector2); vector3 = parent.InverseTransformPoint(vector3); } Vector3 vector6 = (mPanel.hasClipping ? Vector3.zero : mPanel.CalculateConstrainOffset(vector2, vector3)); vector = transform.localPosition + vector6; vector.x = Mathf.Round(vector.x); vector.y = Mathf.Round(vector.y); transform.localPosition = vector; } else { OnSelect(isSelected: false); } } }