using System; using System.Collections.Generic; using UnityEngine; namespace FairyGUI { /// <summary> /// GRoot is a topmost component of UI display list.You dont need to create GRoot. It is created automatically. /// </summary> public class GRoot : GComponent { /// <summary> /// /// </summary> public static float contentScaleFactor { get { return UIContentScaler.scaleFactor; } } /// <summary> /// /// </summary> public static int contentScaleLevel { get { return UIContentScaler.scaleLevel; } } GGraph _modalLayer; GObject _modalWaitPane; List<GObject> _popupStack; List<GObject> _justClosedPopups; HashSet<GObject> _specialPopups; GObject _tooltipWin; GObject _defaultTooltipWin; internal static GRoot _inst; public static GRoot inst { get { if (_inst == null) Stage.Instantiate(); return _inst; } } public GRoot() { this.name = this.rootContainer.name = this.rootContainer.gameObject.name = "GRoot"; this.opaque = false; _popupStack = new List<GObject>(); _justClosedPopups = new List<GObject>(); _specialPopups = new HashSet<GObject>(); Stage.inst.onTouchBegin.AddCapture(__stageTouchBegin); Stage.inst.onTouchEnd.AddCapture(__stageTouchEnd); } override public void Dispose() { base.Dispose(); Stage.inst.onTouchBegin.RemoveCapture(__stageTouchBegin); Stage.inst.onTouchEnd.RemoveCapture(__stageTouchEnd); } /// <summary> /// Set content scale factor. /// </summary> /// <param name="designResolutionX">Design resolution of x axis.</param> /// <param name="designResolutionY">Design resolution of y axis.</param> public void SetContentScaleFactor(int designResolutionX, int designResolutionY) { SetContentScaleFactor(designResolutionX, designResolutionY, UIContentScaler.ScreenMatchMode.MatchWidthOrHeight); } /// <summary> /// Set content scale factor. /// </summary> /// <param name="designResolutionX">Design resolution of x axis.</param> /// <param name="designResolutionY">Design resolution of y axis.</param> /// <param name="screenMatchMode">Match mode.</param> public void SetContentScaleFactor(int designResolutionX, int designResolutionY, UIContentScaler.ScreenMatchMode screenMatchMode) { UIContentScaler scaler = Stage.inst.gameObject.GetComponent<UIContentScaler>(); scaler.designResolutionX = designResolutionX; scaler.designResolutionY = designResolutionY; scaler.scaleMode = UIContentScaler.ScaleMode.ScaleWithScreenSize; scaler.screenMatchMode = screenMatchMode; scaler.ApplyChange(); ApplyContentScaleFactor(); } /// <summary> /// /// </summary> /// <param name="constantScaleFactor"></param> public void SetContentScaleFactor(float constantScaleFactor) { UIContentScaler scaler = Stage.inst.gameObject.GetComponent<UIContentScaler>(); scaler.scaleMode = UIContentScaler.ScaleMode.ConstantPixelSize; scaler.constantScaleFactor = constantScaleFactor; scaler.ApplyChange(); ApplyContentScaleFactor(); } /// <summary> /// This is called after screen size changed. /// </summary> public void ApplyContentScaleFactor() { this.SetSize(Mathf.CeilToInt(Stage.inst.width / UIContentScaler.scaleFactor), Mathf.CeilToInt(Stage.inst.height / UIContentScaler.scaleFactor)); this.SetScale(UIContentScaler.scaleFactor, UIContentScaler.scaleFactor); } /// <summary> /// Display a window. /// </summary> /// <param name="win"></param> public void ShowWindow(Window win) { AddChild(win); AdjustModalLayer(); } /// <summary> /// Call window.Hide /// 关闭一个窗口。将调用Window.Hide方法。 /// </summary> /// <param name="win"></param> public void HideWindow(Window win) { win.Hide(); } /// <summary> /// Remove a window from stage immediatelly. window.Hide/window.OnHide will never be called. ///立刻关闭一个窗口。不会调用Window.Hide方法,Window.OnHide也不会被调用。 /// </summary> /// <param name="win"></param> public void HideWindowImmediately(Window win) { HideWindowImmediately(win, false); } /// <summary> /// Remove a window from stage immediatelly. window.Hide/window.OnHide will never be called. /// 立刻关闭一个窗口。不会调用Window.Hide方法,Window.OnHide也不会被调用。 /// </summary> /// <param name="win"></param> /// <param name="dispose">True to dispose the window.</param> public void HideWindowImmediately(Window win, bool dispose) { if (win.parent == this) RemoveChild(win, dispose); else if (dispose) win.Dispose(); AdjustModalLayer(); } /// <summary> /// 将一个窗口提到所有窗口的最前面 /// </summary> /// <param name="win"></param> public void BringToFront(Window win) { int cnt = this.numChildren; int i; if (_modalLayer != null && _modalLayer.parent != null && !win.modal) i = GetChildIndex(_modalLayer) - 1; else i = cnt - 1; for (; i >= 0; i--) { GObject g = GetChildAt(i); if (g == win) return; if (g is Window) break; } if (i >= 0) SetChildIndex(win, i); } /// <summary> /// Display a modal layer and a waiting sign in the front. /// 显示一个半透明层和一个等待标志在最前面。半透明层的颜色可以通过UIConfig.modalLayerColor设定。 /// 等待标志的资源可以通过UIConfig.globalModalWaiting。等待标志组件会设置为屏幕大小,请内部做好关联。 /// </summary> public void ShowModalWait() { if (UIConfig.globalModalWaiting != null) { if (_modalWaitPane == null || _modalWaitPane.isDisposed) { _modalWaitPane = UIPackage.CreateObjectFromURL(UIConfig.globalModalWaiting); _modalWaitPane.SetHome(this); } _modalWaitPane.SetSize(this.width, this.height); _modalWaitPane.AddRelation(this, RelationType.Size); AddChild(_modalWaitPane); } } /// <summary> /// Hide modal layer and waiting sign. /// </summary> public void CloseModalWait() { if (_modalWaitPane != null && _modalWaitPane.parent != null) RemoveChild(_modalWaitPane); } /// <summary> /// Close all windows except modal windows. /// </summary> public void CloseAllExceptModals() { GObject[] arr = _children.ToArray(); foreach (GObject g in arr) { if ((g is Window) && !(g as Window).modal) HideWindowImmediately(g as Window); } } /// <summary> /// Close all windows. /// </summary> public void CloseAllWindows() { GObject[] arr = _children.ToArray(); foreach (GObject g in arr) { if (g is Window) HideWindowImmediately(g as Window); } } /// <summary> /// Get window on top. /// </summary> /// <returns></returns> public Window GetTopWindow() { int cnt = this.numChildren; for (int i = cnt - 1; i >= 0; i--) { GObject g = this.GetChildAt(i); if (g is Window) { return (Window)(g); } } return null; } /// <summary> /// /// </summary> public GGraph modalLayer { get { if (_modalLayer == null || _modalLayer.isDisposed) CreateModalLayer(); return _modalLayer; } } void CreateModalLayer() { _modalLayer = new GGraph(); _modalLayer.DrawRect(this.width, this.height, 0, Color.white, UIConfig.modalLayerColor); _modalLayer.AddRelation(this, RelationType.Size); _modalLayer.name = _modalLayer.gameObjectName = "ModalLayer"; _modalLayer.SetHome(this); } /// <summary> /// Return true if a modal window is on stage. /// </summary> public bool hasModalWindow { get { return _modalLayer != null && _modalLayer.parent != null; } } /// <summary> /// Return true if modal waiting layer is on stage. /// </summary> public bool modalWaiting { get { return (_modalWaitPane != null) && _modalWaitPane.onStage; } } /// <summary> /// Get current touch target. (including hover) /// </summary> public GObject touchTarget { get { return DisplayObjectToGObject(Stage.inst.touchTarget); } } /// <summary> /// /// </summary> /// <param name="obj"></param> /// <returns></returns> public GObject DisplayObjectToGObject(DisplayObject obj) { while (obj != null) { if (obj.gOwner != null) return obj.gOwner; obj = obj.parent; } return null; } private void AdjustModalLayer() { if (_modalLayer == null || _modalLayer.isDisposed) CreateModalLayer(); int cnt = this.numChildren; if (_modalWaitPane != null && _modalWaitPane.parent != null) SetChildIndex(_modalWaitPane, cnt - 1); for (int i = cnt - 1; i >= 0; i--) { GObject g = this.GetChildAt(i); if ((g is Window) && (g as Window).modal) { if (_modalLayer.parent == null) AddChildAt(_modalLayer, i); else SetChildIndexBefore(_modalLayer, i); return; } } if (_modalLayer.parent != null) RemoveChild(_modalLayer); } /// <summary> /// Show a popup object. /// 显示一个popup。 /// popup的特点是点击popup对象外的区域,popup对象将自动消失。 /// </summary> /// <param name="popup"></param> public void ShowPopup(GObject popup) { ShowPopup(popup, null, PopupDirection.Auto, false); } /// <summary> /// Show a popup object along with the specific target object. /// 显示一个popup。将popup显示在指定对象的上边或者下边。 /// popup的特点是点击popup对象外的区域,popup对象将自动消失。 /// </summary> /// <param name="popup"></param> /// <param name="target"></param> public void ShowPopup(GObject popup, GObject target) { ShowPopup(popup, target, PopupDirection.Auto, false); } [Obsolete] public void ShowPopup(GObject popup, GObject target, object downward) { ShowPopup(popup, target, downward == null ? PopupDirection.Auto : ((bool)downward == true ? PopupDirection.Down : PopupDirection.Up), false); } /// <summary> /// Show a popup object along with the specific target object. /// 显示一个popup。将popup显示在指定对象的上方或者下方。 /// popup的特点是点击popup对象外的区域,popup对象将自动消失。 /// </summary> /// <param name="popup"></param> /// <param name="target"></param> /// <param name="dir"></param> public void ShowPopup(GObject popup, GObject target, PopupDirection dir) { ShowPopup(popup, target, dir, false); } /// <summary> /// Show a popup object along with the specific target object. /// 显示一个popup。将popup显示在指定对象的上方或者下方。 /// popup的特点是点击popup对象外的区域,popup对象将自动消失。 /// 默认情况下,popup在touchEnd事件中关闭;特别设置closeUntilUpEvent=true则可使该popup在touchEnd中才关闭。 /// </summary> /// <param name="popup"></param> /// <param name="target"></param> /// <param name="dir"></param> /// <param name="closeUntilUpEvent"></param> public void ShowPopup(GObject popup, GObject target, PopupDirection dir, bool closeUntilUpEvent) { if (_popupStack.Count > 0) { int k = _popupStack.IndexOf(popup); if (k != -1) { for (int i = _popupStack.Count - 1; i >= k; i--) { int last = _popupStack.Count - 1; GObject obj = _popupStack[last]; ClosePopup(obj); _popupStack.RemoveAt(last); _specialPopups.Remove(obj); } } } _popupStack.Add(popup); if (closeUntilUpEvent) _specialPopups.Add(popup); if (target != null) { GObject p = target; while (p != null) { if (p.parent == this) { if (popup.sortingOrder < p.sortingOrder) { popup.sortingOrder = p.sortingOrder; } break; } p = p.parent; } } AddChild(popup); AdjustModalLayer(); if ((popup is Window) && target == null && dir == PopupDirection.Auto) return; Vector2 pos = GetPoupPosition(popup, target, dir); popup.xy = pos; } [Obsolete] public Vector2 GetPoupPosition(GObject popup, GObject target, object downward) { return GetPoupPosition(popup, target, downward == null ? PopupDirection.Auto : ((bool)downward == true ? PopupDirection.Down : PopupDirection.Up)); } /// <summary> /// /// </summary> /// <param name="popup"></param> /// <param name="target"></param> /// <param name="dir"></param> /// <returns></returns> public Vector2 GetPoupPosition(GObject popup, GObject target, PopupDirection dir) { Vector2 pos; Vector2 size = Vector2.zero; if (target != null) { pos = target.LocalToRoot(Vector2.zero, this); size = target.LocalToRoot(target.size, this) - pos; } else { pos = this.GlobalToLocal(Stage.inst.touchPosition); } float xx, yy; xx = pos.x; if (xx + popup.width > this.width) xx = xx + size.x - popup.width; yy = pos.y + size.y; if ((dir == PopupDirection.Auto && yy + popup.height > this.height) || dir == PopupDirection.Up) { yy = pos.y - popup.height - 1; if (yy < 0) { yy = 0; xx += size.x / 2; } } return new Vector2(Mathf.RoundToInt(xx), Mathf.RoundToInt(yy)); } /// <summary> /// If a popup is showing, then close it; otherwise, open it. /// </summary> /// <param name="popup"></param> public void TogglePopup(GObject popup) { TogglePopup(popup, null, PopupDirection.Auto, false); } /// <summary> /// /// </summary> /// <param name="popup"></param> /// <param name="target"></param> public void TogglePopup(GObject popup, GObject target) { TogglePopup(popup, target, PopupDirection.Auto, false); } [Obsolete] public void TogglePopup(GObject popup, GObject target, object downward) { TogglePopup(popup, target, downward == null ? PopupDirection.Auto : ((bool)downward == true ? PopupDirection.Down : PopupDirection.Up), false); } /// <summary> /// /// </summary> /// <param name="popup"></param> /// <param name="target"></param> /// <param name="dir"></param> public void TogglePopup(GObject popup, GObject target, PopupDirection dir) { TogglePopup(popup, target, dir, false); } /// <summary> /// /// </summary> /// <param name="popup"></param> /// <param name="target"></param> /// <param name="dir"></param> /// <param name="closeUntilUpEvent"></param> public void TogglePopup(GObject popup, GObject target, PopupDirection dir, bool closeUntilUpEvent) { if (_justClosedPopups.IndexOf(popup) != -1) return; ShowPopup(popup, target, dir, closeUntilUpEvent); } /// <summary> /// Close all popups. /// </summary> public void HidePopup() { HidePopup(null); } /// <summary> /// Close a popup. /// </summary> /// <param name="popup"></param> public void HidePopup(GObject popup) { if (popup != null) { int k = _popupStack.IndexOf(popup); if (k != -1) { for (int i = _popupStack.Count - 1; i >= k; i--) { int last = _popupStack.Count - 1; GObject obj = _popupStack[last]; ClosePopup(obj); _popupStack.RemoveAt(last); _specialPopups.Remove(obj); } } } else { foreach (GObject obj in _popupStack) ClosePopup(obj); _popupStack.Clear(); _specialPopups.Clear(); } } /// <summary> /// /// </summary> public bool hasAnyPopup { get { return _popupStack.Count > 0; } } void ClosePopup(GObject target) { if (target.parent != null) { if (target is Window) ((Window)target).Hide(); else RemoveChild(target); } } /// <summary> /// /// </summary> /// <param name="msg"></param> public void ShowTooltips(string msg) { ShowTooltips(msg, 0.1f); } /// <summary> /// /// </summary> /// <param name="msg"></param> /// <param name="delay"></param> public void ShowTooltips(string msg, float delay) { if (_defaultTooltipWin == null || _defaultTooltipWin.isDisposed) { string resourceURL = UIConfig.tooltipsWin; if (string.IsNullOrEmpty(resourceURL)) { Debug.LogWarning("FairyGUI: UIConfig.tooltipsWin not defined"); return; } _defaultTooltipWin = UIPackage.CreateObjectFromURL(resourceURL); _defaultTooltipWin.SetHome(this); _defaultTooltipWin.touchable = false; } _defaultTooltipWin.text = msg; ShowTooltipsWin(_defaultTooltipWin, delay); } /// <summary> /// /// </summary> /// <param name="tooltipWin"></param> public void ShowTooltipsWin(GObject tooltipWin) { ShowTooltipsWin(tooltipWin, 0.1f); } /// <summary> /// /// </summary> /// <param name="tooltipWin"></param> /// <param name="delay"></param> public void ShowTooltipsWin(GObject tooltipWin, float delay) { HideTooltips(); _tooltipWin = tooltipWin; Timers.inst.Add(delay, 1, __showTooltipsWin); } void __showTooltipsWin(object param) { if (_tooltipWin == null) return; float xx = Stage.inst.touchPosition.x + 10; float yy = Stage.inst.touchPosition.y + 20; Vector2 pt = this.GlobalToLocal(new Vector2(xx, yy)); xx = pt.x; yy = pt.y; if (xx + _tooltipWin.width > this.width) xx = xx - _tooltipWin.width; if (yy + _tooltipWin.height > this.height) { yy = yy - _tooltipWin.height - 1; if (yy < 0) yy = 0; } _tooltipWin.x = Mathf.RoundToInt(xx); _tooltipWin.y = Mathf.RoundToInt(yy); AddChild(_tooltipWin); } /// <summary> /// /// </summary> public void HideTooltips() { if (_tooltipWin != null) { if (_tooltipWin.parent != null) RemoveChild(_tooltipWin); _tooltipWin = null; } } /// <summary> /// /// </summary> public GObject focus { get { GObject obj = DisplayObjectToGObject(Stage.inst.focus); if (obj != null && !IsAncestorOf(obj)) return null; else return obj; } set { if (value == null) Stage.inst.focus = null; else Stage.inst.focus = value.displayObject; } } void __stageTouchBegin(EventContext context) { if (_tooltipWin != null) HideTooltips(); CheckPopups(true); } void __stageTouchEnd(EventContext context) { CheckPopups(false); } void CheckPopups(bool touchBegin) { if (touchBegin) _justClosedPopups.Clear(); if (_popupStack.Count > 0) { DisplayObject mc = Stage.inst.touchTarget as DisplayObject; bool handled = false; while (mc != Stage.inst && mc != null) { if (mc.gOwner != null) { int k = _popupStack.IndexOf(mc.gOwner); if (k != -1) { for (int i = _popupStack.Count - 1; i > k; i--) { int last = _popupStack.Count - 1; GObject popup = _popupStack[last]; if (touchBegin == _specialPopups.Contains(popup)) continue; ClosePopup(popup); _justClosedPopups.Add(popup); _popupStack.RemoveAt(last); _specialPopups.Remove(popup); } handled = true; break; } } mc = mc.parent; } if (!handled) { for (int i = _popupStack.Count - 1; i >= 0; i--) { GObject popup = _popupStack[i]; if (touchBegin == _specialPopups.Contains(popup)) continue; ClosePopup(popup); _justClosedPopups.Add(popup); _popupStack.RemoveAt(i); _specialPopups.Remove(popup); } } } } /// <summary> /// /// </summary> public void EnableSound() { Stage.inst.EnableSound(); } /// <summary> /// /// </summary> public void DisableSound() { Stage.inst.DisableSound(); } /// <summary> /// /// </summary> /// <param name="clip"></param> /// <param name="volumeScale"></param> public void PlayOneShotSound(AudioClip clip, float volumeScale) { Stage.inst.PlayOneShotSound(clip, volumeScale); } /// <summary> /// /// </summary> /// <param name="clip"></param> public void PlayOneShotSound(AudioClip clip) { Stage.inst.PlayOneShotSound(clip); } /// <summary> /// /// </summary> public float soundVolume { get { return Stage.inst.soundVolume; } set { Stage.inst.soundVolume = value; } } } }