//---------------------------------------------- // NGUI: Next-Gen UI kit // Copyright © 2011-2015 Tasharen Entertainment //---------------------------------------------- using UnityEngine; using System.Collections.Generic; using System.Collections; using System; /// /// Popup list can be used to display pop-up menus and drop-down lists. /// [ExecuteInEditMode] [AddComponentMenu("NGUI/Interaction/Popup List")] public class UIPopupList : UIWidgetContainer { /// /// Current popup list. Only available during the OnSelectionChange event callback. /// static public UIPopupList current; static GameObject mChild; static float mFadeOutComplete = 0f; const float animSpeed = 0.15f; public enum Position { Auto, Above, Below, } /// /// Atlas used by the sprites. /// public UIAtlas atlas; /// /// Font used by the labels. /// public UIFont bitmapFont; /// /// True type font used by the labels. Alternative to specifying a bitmap font ('font'). /// public Font trueTypeFont; /// /// Font used by the popup list. Conveniently wraps both dynamic and bitmap fonts into one property. /// 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; } } } /// /// Size of the font to use for the popup list's labels. /// public int fontSize = 16; /// /// Font style used by the dynamic font. /// public FontStyle fontStyle = FontStyle.Normal; /// /// Name of the sprite used to create the popup's background. /// public string backgroundSprite; /// /// Name of the sprite used to highlight items. /// public string highlightSprite; /// /// Popup list's display style. /// public Position position = Position.Auto; /// /// Label alignment to use. /// public NGUIText.Alignment alignment = NGUIText.Alignment.Left; /// /// New line-delimited list of items. /// public List items = new List(); /// /// You can associate arbitrary data to be associated with your entries if you like. /// The only downside is that this must be done via code. /// public List itemData = new List(); /// /// Amount of padding added to labels. /// public Vector2 padding = new Vector3(4f, 4f); /// /// Color tint applied to labels inside the list. /// public Color textColor = Color.white; /// /// Color tint applied to the background. /// public Color backgroundColor = Color.white; /// /// Color tint applied to the highlighter. /// public Color highlightColor = new Color(225f / 255f, 200f / 255f, 150f / 255f, 1f); /// /// Whether the popup list is animated or not. Disable for better performance. /// public bool isAnimated = true; /// /// Whether the popup list's values will be localized. /// public bool isLocalized = false; /// /// Whether a separate panel will be used to ensure that the popup will appear on top of everything else. /// public bool separatePanel = true; public enum OpenOn { ClickOrTap, RightClick, DoubleClick, Manual, } /// /// What kind of click is needed in order to open the popup list. /// public OpenOn openOn = OpenOn.ClickOrTap; /// /// Callbacks triggered when the popup list gets a new item selection. /// public List onChange = new List(); // Currently selected item [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 = null; [HideInInspector][SerializeField] protected List mLabelList = new List(); [HideInInspector][SerializeField] protected float mBgBorder = 0f; [System.NonSerialized] protected GameObject mSelection; [System.NonSerialized] protected int mOpenFrame = 0; // Deprecated functionality [HideInInspector][SerializeField] GameObject eventReceiver; [HideInInspector][SerializeField] string functionName = "OnSelectionChange"; [HideInInspector][SerializeField] float textScale = 0f; [HideInInspector][SerializeField] UIFont font; // Use 'bitmapFont' instead // This functionality is no longer needed as the same can be achieved by choosing a // OnValueChange notification targeting a label's SetCurrentSelection function. // If your code was list.textLabel = myLabel, change it to: // EventDelegate.Add(list.onChange, lbl.SetCurrentSelection); [HideInInspector][SerializeField] UILabel textLabel; public delegate void LegacyEvent (string val); LegacyEvent mLegacyEvent; [System.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; } } /// /// Whether the popup list is currently open. /// static public bool isOpen { get { return current != null && (mChild != null || mFadeOutComplete > Time.unscaledTime); } } /// /// Current selection. /// public virtual string value { get { return mSelectedItem; } set { mSelectedItem = value; if (mSelectedItem == null) return; #if UNITY_EDITOR if (!Application.isPlaying) return; #endif if (mSelectedItem != null) TriggerCallbacks(); } } /// /// Item data associated with the current selection. /// public virtual object data { get { int index = items.IndexOf(mSelectedItem); return (index > -1) && index < itemData.Count ? itemData[index] : null; } } /// /// Whether the collider is enabled and the widget can be interacted with. /// public bool isColliderEnabled { get { Collider c = GetComponent(); if (c != null) return c.enabled; Collider2D b = GetComponent(); return (b != null && b.enabled); } } [System.Obsolete("Use 'value' instead")] public string selection { get { return value; } set { this.value = value; } } /// /// Whether the popup list is actually usable. /// bool isValid { get { return bitmapFont != null || trueTypeFont != null; } } /// /// Active font size. /// int activeFontSize { get { return (trueTypeFont != null || bitmapFont == null) ? fontSize : bitmapFont.defaultSize; } } /// /// Font scale applied to the popup list's text. /// float activeFontScale { get { return (trueTypeFont != null || bitmapFont == null) ? 1f : (float)fontSize / bitmapFont.defaultSize; } } /// /// Clear the popup list's contents. /// public virtual void Clear () { items.Clear(); itemData.Clear(); } /// /// Add a new item to the popup list. /// public virtual void AddItem (string text) { items.Add(text); itemData.Add(null); } /// /// Add a new item to the popup list. /// public virtual void AddItem (string text, object data) { items.Add(text); itemData.Add(data); } /// /// Remove the specified item. /// public virtual void RemoveItem (string text) { int index = items.IndexOf(text); if (index != -1) { items.RemoveAt(index); itemData.RemoveAt(index); } } /// /// Remove the specified item. /// public virtual void RemoveItemByData (object data) { int index = itemData.IndexOf(data); if (index != -1) { items.RemoveAt(index); itemData.RemoveAt(index); } } [System.NonSerialized] protected bool mExecuting = false; /// /// Trigger all event notification callbacks. /// protected void TriggerCallbacks () { if (!mExecuting) { mExecuting = true; UIPopupList old = current; current = this; // Legacy functionality if (mLegacyEvent != null) mLegacyEvent(mSelectedItem); if (EventDelegate.IsValid(onChange)) { EventDelegate.Execute(onChange); } else if (eventReceiver != null && !string.IsNullOrEmpty(functionName)) { // Legacy functionality support (for backwards compatibility) eventReceiver.SendMessage(functionName, mSelectedItem, SendMessageOptions.DontRequireReceiver); } current = old; mExecuting = false; } } /// /// Remove legacy functionality. /// protected virtual void OnEnable () { if (EventDelegate.IsValid(onChange)) { eventReceiver = null; functionName = null; } // 'font' is no longer used if (font != null) { if (font.isDynamic) { trueTypeFont = font.dynamicFont; fontStyle = font.dynamicFontStyle; mUseDynamicFont = true; } else if (bitmapFont == null) { bitmapFont = font; mUseDynamicFont = false; } font = null; } // 'textScale' is no longer used if (textScale != 0f) { fontSize = (bitmapFont != null) ? Mathf.RoundToInt(bitmapFont.defaultSize * textScale) : 16; textScale = 0f; } // Auto-upgrade to the true type font if (trueTypeFont == null && bitmapFont != null && bitmapFont.isDynamic) { trueTypeFont = bitmapFont.dynamicFont; bitmapFont = null; } } protected bool mUseDynamicFont = false; protected virtual void OnValidate () { Font ttf = trueTypeFont; UIFont fnt = bitmapFont; bitmapFont = null; trueTypeFont = null; if (ttf != null && (fnt == null || !mUseDynamicFont)) { bitmapFont = null; trueTypeFont = ttf; mUseDynamicFont = true; } else if (fnt != null) { // Auto-upgrade from 3.0.2 and earlier if (fnt.isDynamic) { trueTypeFont = fnt.dynamicFont; fontStyle = fnt.dynamicFontStyle; fontSize = fnt.defaultSize; mUseDynamicFont = true; } else { bitmapFont = fnt; mUseDynamicFont = false; } } else { trueTypeFont = ttf; mUseDynamicFont = true; } } /// /// Send out the selection message on start. /// protected virtual void Start () { // Auto-upgrade legacy functionality if (textLabel != null) { EventDelegate.Add(onChange, textLabel.SetCurrentSelection); textLabel = null; #if UNITY_EDITOR NGUITools.SetDirty(this); #endif } // Automatically choose the first item if (Application.isPlaying) { if (string.IsNullOrEmpty(mSelectedItem) && items.Count > 0) mSelectedItem = items[0]; if (!string.IsNullOrEmpty(mSelectedItem)) TriggerCallbacks(); } } /// /// Localize the text label. /// protected virtual void OnLocalize () { if (isLocalized) TriggerCallbacks(); } /// /// Visibly highlight the specified transform by moving the highlight sprite to be over it. /// protected virtual void Highlight (UILabel lbl, bool instant) { if (mHighlight != null) { mHighlightedLabel = lbl; UISpriteData sp = mHighlight.GetAtlasSprite(); if (sp == null) return; Vector3 pos = GetHighlightPosition(); if (!instant && isAnimated) { TweenPosition.Begin(mHighlight.gameObject, 0.1f, pos).method = UITweener.Method.EaseOut; if (!mTweening) { mTweening = true; StartCoroutine("UpdateTweenPosition"); } } else mHighlight.cachedTransform.localPosition = pos; } } /// /// Helper function that calculates where the tweened position should be. /// protected virtual Vector3 GetHighlightPosition () { if (mHighlightedLabel == null || mHighlight == null) return Vector3.zero; UISpriteData sp = mHighlight.GetAtlasSprite(); if (sp == null) return Vector3.zero; float scaleFactor = atlas.pixelSize; float offsetX = sp.borderLeft * scaleFactor; float offsetY = sp.borderTop * scaleFactor; return mHighlightedLabel.cachedTransform.localPosition + new Vector3(-offsetX, offsetY, 1f); } protected bool mTweening = false; /// /// Periodically update the tweened target position. /// It's needed because the popup list animates into view, and the target position changes. /// 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; } /// /// Event function triggered when the mouse hovers over an item. /// protected virtual void OnItemHover (GameObject go, bool isOver) { if (isOver) { UILabel lbl = go.GetComponent(); Highlight(lbl, false); } } /// /// Event function triggered when the drop-down list item gets clicked on. /// protected virtual void OnItemPress (GameObject go, bool isPressed) { if (isPressed) { Select(go.GetComponent(), true); UIEventListener listener = go.GetComponent(); value = listener.parameter as string; UIPlaySound[] sounds = GetComponents(); for (int i = 0, imax = sounds.Length; i < imax; ++i) { UIPlaySound snd = sounds[i]; if (snd.trigger == UIPlaySound.Trigger.OnClick) NGUITools.PlaySound(snd.audioClip, snd.volume, 1f); } CloseSelf(); } } /// /// Select the specified label. /// void Select (UILabel lbl, bool instant) { Highlight(lbl, instant); } /// /// React to key-based input. /// protected virtual void OnNavigate (KeyCode key) { if (enabled && current == this) { int index = mLabelList.IndexOf(mHighlightedLabel); if (index == -1) index = 0; if (key == KeyCode.UpArrow) { if (index > 0) { Select(mLabelList[--index], false); } } else if (key == KeyCode.DownArrow) { if (index + 1 < mLabelList.Count) { Select(mLabelList[++index], false); } } } } /// /// React to key-based input. /// protected virtual void OnKey (KeyCode key) { if (enabled && current == this) { if (key == UICamera.current.cancelKey0 || key == UICamera.current.cancelKey1) OnSelect(false); } } /// /// Close the popup list when disabled. /// protected virtual void OnDisable () { CloseSelf(); } /// /// Get rid of the popup dialog when the selection gets lost. /// protected virtual void OnSelect (bool isSelected) { if (!isSelected) CloseSelf(); } /// /// Manually close the popup list. /// static public void Close () { if (current != null) { current.CloseSelf(); current = null; } } /// /// Manually close the popup list. /// public virtual void CloseSelf () { if (mChild != null && current == this) { StopCoroutine("CloseIfUnselected"); mSelection = null; mLabelList.Clear(); if (isAnimated) { UIWidget[] widgets = mChild.GetComponentsInChildren(); for (int i = 0, imax = widgets.Length; i < imax; ++i) { UIWidget w = widgets[i]; Color c = w.color; c.a = 0f; TweenColor.Begin(w.gameObject, animSpeed, c).method = UITweener.Method.EaseOut; } Collider[] cols = mChild.GetComponentsInChildren(); for (int i = 0, imax = cols.Length; i < imax; ++i) cols[i].enabled = false; Destroy(mChild, animSpeed); mFadeOutComplete = Time.unscaledTime + Mathf.Max(0.1f, animSpeed); } else { Destroy(mChild); mFadeOutComplete = Time.unscaledTime + 0.1f; } mBackground = null; mHighlight = null; mChild = null; current = null; } } /// /// Helper function that causes the widget to smoothly fade in. /// protected virtual void AnimateColor (UIWidget widget) { Color c = widget.color; widget.color = new Color(c.r, c.g, c.b, 0f); TweenColor.Begin(widget.gameObject, animSpeed, c).method = UITweener.Method.EaseOut; } /// /// Helper function that causes the widget to smoothly move into position. /// protected virtual void AnimatePosition (UIWidget widget, bool placeAbove, float bottom) { Vector3 target = widget.cachedTransform.localPosition; Vector3 start = placeAbove ? new Vector3(target.x, bottom, target.z) : new Vector3(target.x, 0f, target.z); widget.cachedTransform.localPosition = start; GameObject go = widget.gameObject; TweenPosition.Begin(go, animSpeed, target).method = UITweener.Method.EaseOut; } /// /// Helper function that causes the widget to smoothly grow until it reaches its original size. /// protected virtual void AnimateScale (UIWidget widget, bool placeAbove, float bottom) { GameObject go = widget.gameObject; Transform t = widget.cachedTransform; float minHeight = activeFontSize * activeFontScale + mBgBorder * 2f; t.localScale = new Vector3(1f, minHeight / widget.height, 1f); TweenScale.Begin(go, animSpeed, Vector3.one).method = UITweener.Method.EaseOut; if (placeAbove) { Vector3 pos = t.localPosition; t.localPosition = new Vector3(pos.x, pos.y - widget.height + minHeight, pos.z); TweenPosition.Begin(go, animSpeed, pos).method = UITweener.Method.EaseOut; } } /// /// Helper function used to animate widgets. /// void Animate (UIWidget widget, bool placeAbove, float bottom) { AnimateColor(widget); AnimatePosition(widget, placeAbove, bottom); } /// /// Display the drop-down list when the game object gets clicked on. /// protected virtual void OnClick () { if (mOpenFrame == Time.frameCount) return; if (mChild == null) { if (openOn == OpenOn.DoubleClick || openOn == OpenOn.Manual) return; if (openOn == OpenOn.RightClick && UICamera.currentTouchID != -2) return; Show(); } else if (mHighlightedLabel != null) { OnItemPress(mHighlightedLabel.gameObject, true); } } /// /// Show the popup list on double-click. /// protected virtual void OnDoubleClick () { if (openOn == OpenOn.DoubleClick) Show(); } /// /// Used to keep an eye on the selected object, closing the popup if it changes. /// IEnumerator CloseIfUnselected () { for (; ; ) { yield return null; if (UICamera.selectedObject != mSelection) { CloseSelf(); break; } } } public GameObject source; /// /// Show the popup list dialog. /// public virtual void Show () { if (enabled && NGUITools.GetActive(gameObject) && mChild == null && atlas != null && isValid && items.Count > 0) { mLabelList.Clear(); StopCoroutine("CloseIfUnselected"); // Ensure the popup's source has the selection UICamera.selectedObject = (UICamera.hoveredObject ?? gameObject); mSelection = UICamera.selectedObject; source = UICamera.selectedObject; if (source == null) { Debug.LogError("Popup list needs a source object..."); return; } mOpenFrame = Time.frameCount; // Automatically locate the panel responsible for this object if (mPanel == null) { mPanel = UIPanel.Find(transform); if (mPanel == null) return; } // Calculate the dimensions of the object triggering the popup list so we can position it below it Vector3 min; Vector3 max; // Create the root object for the list mChild = new GameObject("Drop-down List"); mChild.layer = gameObject.layer; if (separatePanel) { if (GetComponent() != null) { Rigidbody rb = mChild.AddComponent(); rb.isKinematic = true; } else if (GetComponent() != null) { Rigidbody2D rb = mChild.AddComponent(); rb.isKinematic = true; } mChild.AddComponent().depth = 1000000; } current = this; Transform t = mChild.transform; t.parent = mPanel.cachedTransform; Vector3 pos; // Manually triggered popup list on some other game object if (openOn == OpenOn.Manual && mSelection != gameObject) { pos = UICamera.lastEventPosition; min = mPanel.cachedTransform.InverseTransformPoint(mPanel.anchorCamera.ScreenToWorldPoint(pos)); max = min; t.localPosition = min; pos = t.position; } else { Bounds bounds = NGUIMath.CalculateRelativeWidgetBounds(mPanel.cachedTransform, transform, false, false); min = bounds.min; max = bounds.max; t.localPosition = min; pos = t.position; } StartCoroutine("CloseIfUnselected"); //t.localRotation = Quaternion.identity; t.eulerAngles = gameObject.transform.eulerAngles; t.localScale = Vector3.one; // Add a sprite for the background mBackground = NGUITools.AddSprite(mChild, atlas, backgroundSprite, separatePanel ? 0 : NGUITools.CalculateNextDepth(mPanel.gameObject)); mBackground.pivot = UIWidget.Pivot.TopLeft; mBackground.color = backgroundColor; // We need to know the size of the background sprite for padding purposes Vector4 bgPadding = mBackground.border; mBgBorder = bgPadding.y; mBackground.cachedTransform.localPosition = new Vector3(0f, bgPadding.y, 0f); // Add a sprite used for the selection mHighlight = NGUITools.AddSprite(mChild, atlas, highlightSprite, mBackground.depth + 1); mHighlight.pivot = UIWidget.Pivot.TopLeft; mHighlight.color = highlightColor; UISpriteData hlsp = mHighlight.GetAtlasSprite(); if (hlsp == null) return; float hlspHeight = hlsp.borderTop; float fontHeight = activeFontSize; float dynScale = activeFontScale; float labelHeight = fontHeight * dynScale; float x = 0f, y = -padding.y; List labels = new List(); // Clear the selection if it's no longer present if (!items.Contains(mSelectedItem)) mSelectedItem = null; // Run through all items and create labels for each one for (int i = 0, imax = items.Count; i < imax; ++i) { string s = items[i]; UILabel lbl = NGUITools.AddWidget(mChild, mBackground.depth + 2); lbl.name = i.ToString(); lbl.pivot = UIWidget.Pivot.TopLeft; lbl.bitmapFont = bitmapFont; lbl.trueTypeFont = trueTypeFont; lbl.fontSize = fontSize; lbl.fontStyle = fontStyle; lbl.text = isLocalized ? Localization.Get(s) : s; lbl.color = textColor; lbl.cachedTransform.localPosition = new Vector3(bgPadding.x + padding.x - lbl.pivotOffset.x, y, -1f); lbl.overflowMethod = UILabel.Overflow.ResizeFreely; lbl.alignment = alignment; labels.Add(lbl); y -= labelHeight; y -= padding.y; x = Mathf.Max(x, lbl.printedSize.x); // Add an event listener UIEventListener listener = UIEventListener.Get(lbl.gameObject); listener.onHover = OnItemHover; listener.onPress = OnItemPress; listener.onScroll = OnItemScroll; listener.parameter = s; // Move the selection here if this is the right label if (mSelectedItem == s || (i == 0 && string.IsNullOrEmpty(mSelectedItem))) Highlight(lbl, true); // Add this label to the list mLabelList.Add(lbl); } // The triggering widget's width should be the minimum allowed width x = Mathf.Max(x, (max.x - min.x) - (bgPadding.x + padding.x) * 2f); float cx = x; Vector3 bcCenter = new Vector3(cx * 0.5f, -labelHeight * 0.5f, 0f); Vector3 bcSize = new Vector3(cx, (labelHeight + padding.y), 1f); // Run through all labels and add colliders for (int i = 0, imax = labels.Count; i < imax; ++i) { UILabel lbl = labels[i]; NGUITools.AddWidgetCollider(lbl.gameObject); lbl.autoResizeBoxCollider = false; BoxCollider bc = lbl.GetComponent(); if (bc != null) { bcCenter.z = bc.center.z; bc.center = bcCenter; bc.size = bcSize; } else { BoxCollider2D b2d = lbl.GetComponent(); #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 b2d.center = bcCenter; #else b2d.offset = bcCenter; #endif b2d.size = bcSize; } } int lblWidth = Mathf.RoundToInt(x); x += (bgPadding.x + padding.x) * 2f; y -= bgPadding.y; // Scale the background sprite to envelop the entire set of items mBackground.width = Mathf.RoundToInt(x); mBackground.height = Mathf.RoundToInt(-y + bgPadding.y); // Set the label width to make alignment work for (int i = 0, imax = labels.Count; i < imax; ++i) { UILabel lbl = labels[i]; lbl.overflowMethod = UILabel.Overflow.ShrinkContent; lbl.width = lblWidth; } // Scale the highlight sprite to envelop a single item float scaleFactor = 2f * atlas.pixelSize; float w = x - (bgPadding.x + padding.x) * 2f + hlsp.borderLeft * scaleFactor; float h = labelHeight + hlspHeight * scaleFactor; mHighlight.width = Mathf.RoundToInt(w); mHighlight.height = Mathf.RoundToInt(h); bool placeAbove = (position == Position.Above); if (position == Position.Auto) { UICamera cam = UICamera.FindCameraForLayer(mSelection.layer); if (cam != null) { Vector3 viewPos = cam.cachedCamera.WorldToViewportPoint(pos); placeAbove = (viewPos.y < 0.5f); } } // If the list should be animated, let's animate it by expanding it if (isAnimated) { AnimateColor(mBackground); if (Time.timeScale == 0f || Time.timeScale >= 0.1f) { float bottom = y + labelHeight; Animate(mHighlight, placeAbove, bottom); for (int i = 0, imax = labels.Count; i < imax; ++i) Animate(labels[i], placeAbove, bottom); AnimateScale(mBackground, placeAbove, bottom); } } // If we need to place the popup list above the item, we need to reposition everything by the size of the list if (placeAbove) { min.y = max.y - bgPadding.y; max.y = min.y + mBackground.height; max.x = min.x + mBackground.width; t.localPosition = new Vector3(min.x, max.y - bgPadding.y, min.z); } else { max.y = min.y + bgPadding.y; min.y = max.y - mBackground.height; max.x = min.x + mBackground.width; } Transform pt = mPanel.cachedTransform.parent; if (pt != null) { min = mPanel.cachedTransform.TransformPoint(min); max = mPanel.cachedTransform.TransformPoint(max); min = pt.InverseTransformPoint(min); max = pt.InverseTransformPoint(max); } // Ensure that everything fits into the panel's visible range Vector3 offset = mPanel.hasClipping ? Vector3.zero : mPanel.CalculateConstrainOffset(min, max); pos = t.localPosition + offset; pos.x = Mathf.Round(pos.x); pos.y = Mathf.Round(pos.y); t.localPosition = pos; } else OnSelect(false); if (mChild != null) { //if (gameObject.layer == Program.ui_back_ground_2d.layer) //{ // mChild.transform.SetParent(Program.ui_main_2d.transform, true); // var trans = mChild.GetComponentsInChildren(); // foreach (var item in trans) // { // item.gameObject.layer = Program.ui_main_2d.layer; // } //} if (gameObject.layer == Program.ui_main_3d.layer) { mChild.transform.SetParent(Program.ui_main_3d.transform, true); } if (gameObject.layer == Program.ui_windows_2d.layer) { mChild.transform.SetParent(Program.ui_windows_2d.transform, true); } if (gameObject.layer == Program.ui_main_2d.layer) { mChild.transform.SetParent(Program.ui_main_2d.transform, true); } } } float timeScroller = 0; void OnItemScroll(GameObject go, float delta) { var a = go.transform.parent.localPosition; if (go.layer != Program.ui_main_2d.layer&& go.layer != Program.ui_windows_2d.layer) { a.y -= delta * 100f; a.z -= delta * 100f * 1.732f; } else { float whole = items.Count * 20; float l=delta *100f; if (go.layer == Program.ui_windows_2d.layer) { l = delta * 50f; } l *= 1500f / (timeScroller - Program.TimePassed()); if (l > 0) { if (l < 100) { l = 100; } if (l > 500) { l = 500; } } else { if (l > -100) { l = -100; } if (l < -500) { l = -500; } } a.y += l; a.z = 0; timeScroller = Program.TimePassed(); if (a.y > whole) { a.y = whole; } if (a.y < 0) { a.y = 0; } } go.transform.parent.localPosition = a; } }