OverrideScreenProperties.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using UnityEngine;
  6. using UnityEngine.UI;
  7. using UnityEngine.EventSystems;
  8. using System.Collections;
  9. #pragma warning disable 0649 // never assigned warning
  10. namespace TheraBytes.BetterUi
  11. {
  12. #if UNITY_2018_3_OR_NEWER
  13. [ExecuteAlways]
  14. #else
  15. [ExecuteInEditMode]
  16. #endif
  17. [HelpURL("https://documentation.therabytes.de/better-ui/OverrideScreenProperties.html")]
  18. [AddComponentMenu("Better UI/Layout/Override Screen Properties", 30)]
  19. public class OverrideScreenProperties : UIBehaviour, IResolutionDependency
  20. {
  21. public enum ScreenProperty
  22. {
  23. Width,
  24. Height,
  25. Dpi,
  26. }
  27. public enum OverrideMode
  28. {
  29. Override,
  30. Inherit,
  31. ActualScreenProperty,
  32. }
  33. [Serializable]
  34. public class Settings : IScreenConfigConnection
  35. {
  36. [Serializable]
  37. public class OverrideProperty
  38. {
  39. [SerializeField]
  40. OverrideMode mode;
  41. [SerializeField]
  42. float value;
  43. public OverrideMode Mode { get { return mode; } }
  44. public float Value { get { return value; } }
  45. }
  46. public OverrideProperty OptimizedWidthOverride;
  47. public OverrideProperty OptimizedHeightOverride;
  48. public OverrideProperty OptimizedDpiOverride;
  49. public IEnumerable<OverrideProperty> PropertyIterator()
  50. {
  51. yield return OptimizedWidthOverride;
  52. yield return OptimizedHeightOverride;
  53. yield return OptimizedDpiOverride;
  54. }
  55. public OverrideProperty this[ScreenProperty property]
  56. {
  57. get
  58. {
  59. switch (property)
  60. {
  61. case ScreenProperty.Width: return OptimizedWidthOverride;
  62. case ScreenProperty.Height: return OptimizedHeightOverride;
  63. case ScreenProperty.Dpi: return OptimizedDpiOverride;
  64. default: throw new ArgumentException();
  65. }
  66. }
  67. }
  68. [SerializeField]
  69. string screenConfigName;
  70. public string ScreenConfigName { get { return screenConfigName; } set { screenConfigName = value; } }
  71. }
  72. [Serializable]
  73. public class SettingsConfigCollection : SizeConfigCollection<Settings> { }
  74. [SerializeField]
  75. Settings settingsFallback = new Settings();
  76. [SerializeField]
  77. SettingsConfigCollection customSettings = new SettingsConfigCollection();
  78. public Settings CurrentSettings { get { return customSettings.GetCurrentItem(settingsFallback); } }
  79. #if UNITY_EDITOR
  80. public SettingsConfigCollection SettingsList { get { return customSettings; } }
  81. public Settings FallbackSettings { get { return settingsFallback; } }
  82. #endif
  83. ScreenInfo optimizedOverride = new ScreenInfo();
  84. ScreenInfo currentOverride = new ScreenInfo();
  85. public ScreenInfo OptimizedOverride { get { return optimizedOverride; } }
  86. public ScreenInfo CurrentSize { get { return currentOverride; } }
  87. protected override void OnEnable()
  88. {
  89. base.OnEnable();
  90. OnResolutionChanged();
  91. }
  92. protected override void OnTransformParentChanged()
  93. {
  94. base.OnTransformParentChanged();
  95. OnResolutionChanged();
  96. }
  97. protected override void OnRectTransformDimensionsChange()
  98. {
  99. base.OnRectTransformDimensionsChange();
  100. OnResolutionChanged();
  101. }
  102. public void OnResolutionChanged()
  103. {
  104. // unfortunately the dimension is updated delayed and the UI-interfaces do not work (at least not for all supported unity versions)
  105. // so we simply wait a frame, before updating the sizes.
  106. StopAllCoroutines();
  107. StartCoroutine(RecalculateRoutine());
  108. }
  109. IEnumerator RecalculateRoutine()
  110. {
  111. yield return null;
  112. var settings = customSettings.GetCurrentItem(settingsFallback);
  113. Recalculate(settings);
  114. // let all children recalculate now
  115. InformChildren();
  116. }
  117. private void Recalculate(Settings settings)
  118. {
  119. OverrideScreenProperties parent = (settings.PropertyIterator().Any(o => o.Mode == OverrideMode.Inherit))
  120. ? this.GetComponentInParent<OverrideScreenProperties>()
  121. : null;
  122. float optimizedWidth = CalculateOptimizedValue(settings, ScreenProperty.Width, parent);
  123. float optimizedHeight = CalculateOptimizedValue(settings, ScreenProperty.Height, parent);
  124. float optimizedDpi = CalculateOptimizedValue(settings, ScreenProperty.Dpi, parent);
  125. optimizedOverride.Resolution = new Vector2(optimizedWidth, optimizedHeight);
  126. optimizedOverride.Dpi = optimizedDpi;
  127. Rect rect = new Rect();
  128. if (settings.PropertyIterator().Any(o => o.Mode == OverrideMode.Override))
  129. {
  130. rect = (this.transform as RectTransform).rect;
  131. };
  132. float currentWidth = CalculateCurrentValue(settings, ScreenProperty.Width, parent, rect);
  133. float currentHeight = CalculateCurrentValue(settings, ScreenProperty.Height, parent, rect);
  134. float currentDpi = CalculateCurrentValue(settings, ScreenProperty.Dpi, parent, rect);
  135. currentOverride.Resolution = new Vector2(currentWidth, currentHeight);
  136. currentOverride.Dpi = currentDpi;
  137. }
  138. public float CalculateOptimizedValue(Settings settings, ScreenProperty property, OverrideScreenProperties parent)
  139. {
  140. switch(settings[property].Mode)
  141. {
  142. case OverrideMode.Override:
  143. return settings[property].Value;
  144. case OverrideMode.Inherit:
  145. if (parent != null)
  146. {
  147. switch (parent.CurrentSettings[property].Mode)
  148. {
  149. case OverrideMode.Override:
  150. return parent.CurrentSettings[property].Value;
  151. case OverrideMode.Inherit:
  152. OverrideScreenProperties parentParent = parent.GetComponentsInParent<OverrideScreenProperties>().FirstOrDefault(o => o.gameObject != this.gameObject);
  153. return parent.CalculateOptimizedValue(parent.CurrentSettings, property, parentParent);
  154. case OverrideMode.ActualScreenProperty: break;
  155. }
  156. }
  157. // If parent is null or parent uses actual screen property:
  158. // Fall through!
  159. goto case OverrideMode.ActualScreenProperty;
  160. case OverrideMode.ActualScreenProperty:
  161. ScreenInfo info = ResolutionMonitor.GetOpimizedScreenInfo(settings.ScreenConfigName);
  162. switch (property)
  163. {
  164. case ScreenProperty.Width: return info.Resolution.x;
  165. case ScreenProperty.Height: return info.Resolution.y;
  166. case ScreenProperty.Dpi: return info.Dpi;
  167. default: throw new ArgumentException(); ;
  168. }
  169. }
  170. throw new ArgumentException();
  171. }
  172. private float CalculateCurrentValue(Settings settings, ScreenProperty property, OverrideScreenProperties parent, Rect rect)
  173. {
  174. switch (settings[property].Mode)
  175. {
  176. case OverrideMode.Override:
  177. switch (property)
  178. {
  179. case ScreenProperty.Width: return rect.width;
  180. case ScreenProperty.Height: return rect.height;
  181. case ScreenProperty.Dpi: break;
  182. };
  183. // DPI case: Fall through!
  184. goto case OverrideMode.ActualScreenProperty;
  185. case OverrideMode.Inherit:
  186. if (parent != null)
  187. {
  188. switch (parent.CurrentSettings[property].Mode)
  189. {
  190. case OverrideMode.Override:
  191. Rect parentRect = (parent.transform as RectTransform).rect;
  192. return parent.CalculateCurrentValue(parent.CurrentSettings, property, null, parentRect);
  193. case OverrideMode.Inherit:
  194. OverrideScreenProperties parentParent = parent.GetComponentsInParent<OverrideScreenProperties>().FirstOrDefault(o => o.gameObject != this.gameObject);
  195. return parent.CalculateCurrentValue(parent.CurrentSettings, property, parentParent, new Rect());
  196. case OverrideMode.ActualScreenProperty: break;
  197. }
  198. }
  199. // If parent is null or parent uses actual screen property:
  200. // Fall through!
  201. goto case OverrideMode.ActualScreenProperty;
  202. case OverrideMode.ActualScreenProperty:
  203. switch (property)
  204. {
  205. case ScreenProperty.Width: return ResolutionMonitor.CurrentResolution.x;
  206. case ScreenProperty.Height: return ResolutionMonitor.CurrentResolution.y;
  207. case ScreenProperty.Dpi: return ResolutionMonitor.CurrentDpi;
  208. default: throw new ArgumentException(); ;
  209. }
  210. }
  211. throw new ArgumentException();
  212. }
  213. public void InformChildren()
  214. {
  215. var resDeps = this.GetComponentsInChildren<Component>().OfType<IResolutionDependency>();
  216. foreach (IResolutionDependency comp in resDeps)
  217. {
  218. if (comp.Equals(this))
  219. continue;
  220. comp.OnResolutionChanged();
  221. }
  222. }
  223. }
  224. }
  225. #pragma warning restore 0649