namespace UIWidgets { using System; using System.Collections.Generic; using UnityEngine; /// /// Layout switcher. /// [ExecuteInEditMode] [DisallowMultipleComponent] [AddComponentMenu("UI/New UI Widgets/Layout/Layout Switcher")] public class LayoutSwitcher : MonoBehaviour, IUpdatable { /// /// The tracked objects. /// [SerializeField] protected List Objects = new List(); /// /// The layouts. /// [SerializeField] public List Layouts = new List(); /// /// Layout changed event. /// [SerializeField] public LayoutSwitcherEvent LayoutChanged = new LayoutSwitcherEvent(); /// /// The default display size. /// [SerializeField] [Tooltip("Display size used when actual display size cannot be detected.")] public float DefaultDisplaySize; /// /// Window width. /// protected int WindowWidth; /// /// Window height. /// protected int WindowHeight; /// /// Function to select layout. /// protected Func, float, float, UILayout> layoutSelector = DefaultLayoutSelector; /// /// Function to select layout. /// public virtual Func, float, float, UILayout> LayoutSelector { get { return layoutSelector; } set { layoutSelector = value; ResolutionChanged(); } } /// /// Process the enable event. /// protected virtual void OnEnable() { Updater.Add(this); } /// /// Process the disable event. /// protected virtual void OnDisable() { Updater.Remove(this); } /// /// Update this instance. /// public virtual void RunUpdate() { if (WindowWidth != Screen.width || WindowHeight != Screen.height) { WindowWidth = Screen.width; WindowHeight = Screen.height; ResolutionChanged(); } } /// /// Saves the layout. /// /// Layout. public virtual void SaveLayout(UILayout layout) { layout.Save(Objects); } /// /// Load layout when resolution changed. /// public virtual void ResolutionChanged() { var currentLayout = GetCurrentLayout(); if (currentLayout == null) { return; } currentLayout.Load(); LayoutChanged.Invoke(currentLayout); } /// /// Gets the current layout. /// /// The current layout. public virtual UILayout GetCurrentLayout() { if (Layouts.Count == 0) { return null; } return LayoutSelector(Layouts, DisplaySize(), AspectRatio()); } /// /// Default layout select. /// /// Available layouts. /// Display size in inches. /// Aspect ratio. /// Layout to use. public static UILayout DefaultLayoutSelector(List layouts, float displaySize, float aspectRatio) { var filtered = FilterLayouts(layouts, displaySize, aspectRatio); if (filtered.Count == 0) { return null; } for (int i = 0; i < filtered.Count; i++) { if (displaySize < filtered[i].MaxDisplaySize) { return filtered[i]; } } return filtered[0]; } /// /// Filter layouts by aspect ratio and display size. /// /// Layouts. /// Display size. /// Aspect ratio. /// Filtered layouts. protected static List FilterLayouts(List layouts, float displaySize, float aspectRatio) { var layouts_ar = new List(); for (int i = 0; i < layouts.Count; i++) { var layout = layouts[i]; var diff = Mathf.Abs(aspectRatio - (layout.AspectRatio.x / layout.AspectRatio.y)); if (diff < 0.05f) { layouts_ar.Add(layout); } } layouts_ar.Sort(new DisplaySizeComparer(displaySize).Compare); return layouts_ar; } /// /// Display size comparer. /// protected class DisplaySizeComparer : IEquatable { readonly float DisplaySize; /// /// Initializes a new instance of the class. /// /// Display size. public DisplaySizeComparer(float displaySize) { DisplaySize = displaySize; } /// /// Compare layouts by display size. /// /// First layout. /// Second layout. /// Result of the comparison. public int Compare(UILayout x, UILayout y) { var x_ds = Mathf.Abs(x.MaxDisplaySize - DisplaySize); var y_ds = Mathf.Abs(y.MaxDisplaySize - DisplaySize); return x_ds.CompareTo(y_ds); } /// /// Determines whether the specified object is equal to the current object. /// /// The object to compare with the current object. /// true if the specified object is equal to the current object; otherwise, false. public override bool Equals(object obj) { if (obj is DisplaySizeComparer) { return Equals((DisplaySizeComparer)obj); } return false; } /// /// Determines whether the specified object is equal to the current object. /// /// The object to compare with the current object. /// true if the specified object is equal to the current object; otherwise, false. public bool Equals(DisplaySizeComparer other) { if (ReferenceEquals(other, null)) { return false; } return DisplaySize == other.DisplaySize; } /// /// Hash function. /// /// A hash code for the current object. public override int GetHashCode() { return DisplaySize.GetHashCode(); } /// /// Compare specified instances. /// /// Left instance. /// Right instances. /// true if the instances are equal; otherwise, false. public static bool operator ==(DisplaySizeComparer left, DisplaySizeComparer right) { if (ReferenceEquals(left, null)) { return ReferenceEquals(right, null); } return left.Equals(right); } /// /// Compare specified instances. /// /// Left instance. /// Right instances. /// true if the instances are now equal; otherwise, false. public static bool operator !=(DisplaySizeComparer left, DisplaySizeComparer right) { return !(left == right); } } /// /// Current aspect ratio. /// /// The ratio. public virtual float AspectRatio() { return (float)WindowWidth / (float)WindowHeight; } /// /// Current display size. /// /// The size. public virtual float DisplaySize() { if (Screen.dpi == 0) { return DefaultDisplaySize; } return Mathf.Sqrt(WindowWidth ^ 2 + WindowHeight ^ 2) / Screen.dpi; } } }