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;
}
}
}