GameViewHelper.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. 
  2. /*WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW*\ ( ( ) )
  3. |/ \| ) ) _((_
  4. || (c) Wanzyee Studio < wanzyeestudio.blogspot.com > || ( ( |_ _ |=n
  5. |\ /| _____)) | ! ] U
  6. \.ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ./ (_(__(S) |___*/
  7. using UnityEditor;
  8. using System;
  9. using System.Reflection;
  10. namespace WanzyeeStudio.Editrix.Toolkit{
  11. /// <summary>
  12. /// Helper to undock and fix current Game view size in pixel unit absolutely.
  13. /// </summary>
  14. ///
  15. /// <remarks>
  16. /// Apply by clicking menu "Window/View/Fix Game View Size".
  17. /// The target window found by the order below:
  18. /// 1. Game view with mouse over.
  19. /// 2. Current focused Game view.
  20. /// 3. The main Game view.
  21. /// </remarks>
  22. ///
  23. /// <remarks>
  24. /// It's useful to preview the real size in Game view, pixel by pixel, not ratio scaled.
  25. /// Set window to selected size on the aspect drop-down menu, only for "Fixed Resolution".
  26. /// Use this to easily set size and save presets with the built-in feature.
  27. /// It might be incorrect if the size is too big to close even over the monitor.
  28. /// </remarks>
  29. ///
  30. /// <remarks>
  31. /// Note, this works by reflection to access internal classes.
  32. /// We'd try to keep it up-to-date, but can't guarantee.
  33. /// </remarks>
  34. ///
  35. /*
  36. * http://answers.unity3d.com/questions/179775/
  37. */
  38. public static class GameViewHelper{
  39. #region Menu
  40. /// <summary>
  41. /// Resize game view to selected fixed resolution.
  42. /// </summary>
  43. [MenuItem("Window/View/Fix Game View Size", false, 205)]
  44. public static void FixGameViewSize(){
  45. if(FixGameViewSizeValid()) FixSize();
  46. else throw new MissingMemberException("Some reflections invalid.");
  47. }
  48. /// <summary>
  49. /// Check if <c>FixGameViewSize()</c> valid, resizable window existing.
  50. /// </summary>
  51. /// <returns><c>true</c>, if valid.</returns>
  52. [MenuItem("Window/View/Fix Game View Size", true)]
  53. private static bool FixGameViewSizeValid(){
  54. EditorWindow _w;
  55. object _s;
  56. return GetResizable(out _w, out _s);
  57. }
  58. #endregion
  59. #region Fields
  60. /// <summary>
  61. /// Type of Game view window.
  62. /// </summary>
  63. private static readonly Type _windowType = Type.GetType("UnityEditor.GameView, UnityEditor");
  64. /// <summary>
  65. /// Type of <c>UnityEditor.GameViewSize</c>.
  66. /// With custom setting info of game view resolution, not the displayed.
  67. /// </summary>
  68. private static readonly Type _sizeType = Type.GetType("UnityEditor.GameViewSize, UnityEditor");
  69. /// <summary>
  70. /// Method info to get main game view.
  71. /// Reflect to <c>UnityEditor.GameView.GetMainGameView()</c>.
  72. /// It's a private static method, without params, return <c>UnityEditor.GameView</c>.
  73. /// </summary>
  74. private static readonly MethodInfo _mainMehtod = new Func<MethodInfo>(() => {
  75. if(null == _windowType) return null;
  76. var _b = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
  77. var _m = _windowType.GetMethod("GetMainGameView", _b, null, new Type[0], null);
  78. return (_windowType == _m.ReturnType) ? _m : null;
  79. })();
  80. /// <summary>
  81. /// Property info to get current setting of game view size.
  82. /// Reflect to <c>UnityEditor.GameView.currentGameViewSize</c>.
  83. /// It's a private instance property, without indexer, return <c>UnityEditor.GameViewSize</c>.
  84. /// </summary>
  85. private static readonly PropertyInfo _sizeProp = (
  86. FindProperty(_windowType, "currentGameViewSize", _sizeType)
  87. );
  88. /// <summary>
  89. /// Property info to get type of game view size, 0 as AspectRatio, 1 as FixedResolution.
  90. /// Reflect to <c>UnityEditor.GameViewSize.sizeType</c>.
  91. /// It's a public instance property, without indexer, return <c>UnityEditor.GameViewSizeType</c>.
  92. /// </summary>
  93. private static readonly PropertyInfo _sizeTypeProp = FindProperty(
  94. _sizeType,
  95. "sizeType",
  96. Type.GetType("UnityEditor.GameViewSizeType, UnityEditor")
  97. );
  98. /// <summary>
  99. /// Property info to get width of game view size.
  100. /// Reflect to <c>UnityEditor.GameViewSize.width</c>.
  101. /// It's a public instance property, without indexer, return <c>int</c>.
  102. /// </summary>
  103. private static readonly PropertyInfo _widthProp = (
  104. FindProperty(_sizeType, "width", typeof(int))
  105. );
  106. /// <summary>
  107. /// Property info to get height of game view size.
  108. /// Reflect to <c>UnityEditor.GameViewSize.height</c>.
  109. /// It's a public instance property, without indexer, return <c>int</c>.
  110. /// </summary>
  111. private static readonly PropertyInfo _heightProp = (
  112. FindProperty(_sizeType, "height", typeof(int))
  113. );
  114. #endregion
  115. #region Methods
  116. /// <summary>
  117. /// Get the instance property of specific define type by name and return type.
  118. /// </summary>
  119. /// <returns>The game view size property.</returns>
  120. /// <param name="defineType">Define type.</param>
  121. /// <param name="name">Name.</param>
  122. /// <param name="returnType">Return type.</param>
  123. private static PropertyInfo FindProperty(Type defineType, string name, Type returnType){
  124. if(null == returnType || null == defineType) return null;
  125. var _b = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
  126. return defineType.GetProperty(name, _b, null, returnType, new Type[0], null);
  127. }
  128. /// <summary>
  129. /// Undock and fix current game view size in pixel unit.
  130. /// Set window size as Aspect Drop-Down menu, only for fixed resolution.
  131. /// </summary>
  132. private static void FixSize(){
  133. EditorWindow _w;
  134. object _s;
  135. if(!GetResizable(out _w, out _s)) return;
  136. var _p = _w.position; //get origin
  137. _p.width = (int)_widthProp.GetValue(_s, null);
  138. _p.height = (int)_heightProp.GetValue(_s, null) + 17; //plus control bar
  139. _w.position = _p; //first set back, make window out of dock
  140. _w.position = _p; //double set to make sure resize
  141. }
  142. /// <summary>
  143. /// Get game view and check if able to fix size.
  144. /// Check reflections first, then try to get and check values used.
  145. /// Also valid for FixedResolution only.
  146. /// </summary>
  147. /// <returns><c>true</c>, if able to fix size.</returns>
  148. /// <param name="window">GameView Window.</param>
  149. /// <param name="size">GameViewSize.</param>
  150. private static bool GetResizable(out EditorWindow window, out object size){
  151. window = null;
  152. size = null;
  153. if(null == _mainMehtod || null == _sizeProp) return false;
  154. if(null == _sizeTypeProp || null == _widthProp || null == _heightProp) return false;
  155. window = GetCurrent();
  156. if(null == window) return false;
  157. size = _sizeProp.GetValue(window, null);
  158. return (null != size) && (1 == (int)_sizeTypeProp.GetValue(size, null));
  159. }
  160. /// <summary>
  161. /// Get the current game view.
  162. /// Window with mouse over first, then focused, otherwise find main.
  163. /// </summary>
  164. /// <returns>The current window.</returns>
  165. private static EditorWindow GetCurrent(){
  166. if(_windowType.IsInstanceOfType(EditorWindow.mouseOverWindow)) return EditorWindow.mouseOverWindow;
  167. else if(_windowType.IsInstanceOfType(EditorWindow.focusedWindow)) return EditorWindow.focusedWindow;
  168. else return _mainMehtod.Invoke(null, null) as EditorWindow;
  169. }
  170. #endregion
  171. }
  172. }