Skip to content

Commit 0137d70

Browse files
committed
feat: Add windowed and resolution options
1 parent c749bc7 commit 0137d70

19 files changed

+2395
-340
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#if UNITY_EDITOR
2+
using System;
3+
using System.Reflection;
4+
using UnityEditor;
5+
6+
/// <summary>
7+
/// Found in https://discussions.unity.com/t/how-to-change-game-window-resoltuion-width-height-in-editor-mode-programmatically/861042/3
8+
/// </summary>
9+
public static class GameViewUtils
10+
{
11+
static object gameViewSizesInstance;
12+
static MethodInfo getGroup;
13+
14+
static GameViewUtils()
15+
{
16+
// gameViewSizesInstance = ScriptableSingleton<GameViewSizes>.instance;
17+
var sizesType = typeof(Editor).Assembly.GetType("UnityEditor.GameViewSizes");
18+
var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType);
19+
var instanceProp = singleType.GetProperty("instance");
20+
getGroup = sizesType.GetMethod("GetGroup");
21+
gameViewSizesInstance = instanceProp.GetValue(null, null);
22+
}
23+
24+
public enum GameViewSizeType
25+
{
26+
AspectRatio, FixedResolution
27+
}
28+
29+
public static void SetSize(int index)
30+
{
31+
var gvWndType = typeof(Editor).Assembly.GetType("UnityEditor.GameView");
32+
var selectedSizeIndexProp = gvWndType.GetProperty("selectedSizeIndex",
33+
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
34+
var gvWnd = EditorWindow.GetWindow(gvWndType);
35+
selectedSizeIndexProp.SetValue(gvWnd, index, null);
36+
}
37+
38+
public static void AddAndSelectCustomSize(GameViewSizeType viewSizeType, GameViewSizeGroupType sizeGroupType, int width, int height, string text)
39+
{
40+
int idx = FindSize(GameViewSizeGroupType.Standalone, width, height);
41+
42+
// Add if doesn't exists.
43+
if (idx == -1)
44+
{
45+
AddCustomSize(viewSizeType, sizeGroupType, width, height, text);
46+
idx = FindSize(GameViewSizeGroupType.Standalone, width, height);
47+
}
48+
49+
SetSize(idx);
50+
}
51+
52+
public static void AddCustomSize(GameViewSizeType viewSizeType, GameViewSizeGroupType sizeGroupType, int width, int height, string text)
53+
{
54+
var group = GetGroup(sizeGroupType);
55+
var addCustomSize = getGroup.ReturnType.GetMethod("AddCustomSize"); // or group.GetType().
56+
var gvsType = typeof(Editor).Assembly.GetType("UnityEditor.GameViewSize");
57+
string assemblyName = "UnityEditor.dll";
58+
Assembly assembly = Assembly.Load(assemblyName);
59+
Type gameViewSize = assembly.GetType("UnityEditor.GameViewSize");
60+
Type gameViewSizeType = assembly.GetType("UnityEditor.GameViewSizeType");
61+
ConstructorInfo ctor = gameViewSize.GetConstructor(new Type[]
62+
{
63+
gameViewSizeType,
64+
typeof(int),
65+
typeof(int),
66+
typeof(string)
67+
});
68+
var newSize = ctor.Invoke(new object[] { (int)viewSizeType, width, height, text });
69+
addCustomSize.Invoke(group, new object[] { newSize });
70+
}
71+
72+
public static bool SizeExists(GameViewSizeGroupType sizeGroupType, string text)
73+
{
74+
return FindSize(sizeGroupType, text) != -1;
75+
}
76+
77+
public static int FindSize(GameViewSizeGroupType sizeGroupType, string text)
78+
{
79+
// GameViewSizes group = gameViewSizesInstance.GetGroup(sizeGroupType);
80+
// string[] texts = group.GetDisplayTexts();
81+
// for loop...
82+
83+
var group = GetGroup(sizeGroupType);
84+
var getDisplayTexts = group.GetType().GetMethod("GetDisplayTexts");
85+
var displayTexts = getDisplayTexts.Invoke(group, null) as string[];
86+
for (int i = 0; i < displayTexts.Length; i++)
87+
{
88+
string display = displayTexts[i];
89+
// the text we get is "Name (W:H)" if the size has a name, or just "W:H" e.g. 16:9
90+
// so if we're querying a custom size text we substring to only get the name
91+
// You could see the outputs by just logging
92+
// Debug.Log(display);
93+
int pren = display.IndexOf('(');
94+
if (pren != -1)
95+
display = display.Substring(0, pren - 1); // -1 to remove the space that's before the prens. This is very implementation-depdenent
96+
if (display == text)
97+
return i;
98+
}
99+
return -1;
100+
}
101+
102+
public static bool SizeExists(GameViewSizeGroupType sizeGroupType, int width, int height)
103+
{
104+
return FindSize(sizeGroupType, width, height) != -1;
105+
}
106+
107+
public static int FindSize(GameViewSizeGroupType sizeGroupType, int width, int height)
108+
{
109+
// goal:
110+
// GameViewSizes group = gameViewSizesInstance.GetGroup(sizeGroupType);
111+
// int sizesCount = group.GetBuiltinCount() + group.GetCustomCount();
112+
// iterate through the sizes via group.GetGameViewSize(int index)
113+
114+
var group = GetGroup(sizeGroupType);
115+
var groupType = group.GetType();
116+
var getBuiltinCount = groupType.GetMethod("GetBuiltinCount");
117+
var getCustomCount = groupType.GetMethod("GetCustomCount");
118+
int sizesCount = (int)getBuiltinCount.Invoke(group, null) + (int)getCustomCount.Invoke(group, null);
119+
var getGameViewSize = groupType.GetMethod("GetGameViewSize");
120+
var gvsType = getGameViewSize.ReturnType;
121+
var widthProp = gvsType.GetProperty("width");
122+
var heightProp = gvsType.GetProperty("height");
123+
var indexValue = new object[1];
124+
for (int i = 0; i < sizesCount; i++)
125+
{
126+
indexValue[0] = i;
127+
var size = getGameViewSize.Invoke(group, indexValue);
128+
int sizeWidth = (int)widthProp.GetValue(size, null);
129+
int sizeHeight = (int)heightProp.GetValue(size, null);
130+
if (sizeWidth == width && sizeHeight == height)
131+
return i;
132+
}
133+
return -1;
134+
}
135+
136+
static object GetGroup(GameViewSizeGroupType type)
137+
{
138+
return getGroup.Invoke(gameViewSizesInstance, new object[] { (int)type });
139+
}
140+
141+
public static GameViewSizeGroupType GetCurrentGroupType()
142+
{
143+
var getCurrentGroupTypeProp = gameViewSizesInstance.GetType().GetProperty("currentGroupType");
144+
return (GameViewSizeGroupType)(int)getCurrentGroupTypeProp.GetValue(gameViewSizesInstance, null);
145+
}
146+
}
147+
#endif

Assets/JCSUnity/Scripts/Tools/GameViewUtils.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
using System.Collections.Generic;
2+
using UnityEngine;
3+
using TMPro;
4+
using MyBox;
5+
6+
#if UNITY_EDITOR
7+
using UnityEditor;
8+
#endif
9+
10+
namespace JCSUnity
11+
{
12+
/// <summary>
13+
/// A dropdown menu let you choose the screen resolution.
14+
/// </summary>
15+
[RequireComponent(typeof(TMP_Dropdown))]
16+
public class JCS_DropdownScreenResolution : MonoBehaviour
17+
{
18+
/* Variables */
19+
20+
private TMP_Dropdown mDropdown = null;
21+
22+
[Separator("Initialize Variables (JCS_DropdownScreenResolution)")]
23+
24+
[Tooltip("A list of resolutions to use.")]
25+
[SerializeField]
26+
private List<string> mResolutions = null;
27+
28+
[Tooltip("If true, remove all other options at the beginning.")]
29+
[SerializeField]
30+
private bool mRemoveAllOptions = true;
31+
32+
/* Setter & Getter */
33+
34+
public List<string> Resolutions { get { return mResolutions; } set { this.mResolutions = value; } }
35+
public bool RemoveAllOptions { get { return mRemoveAllOptions; } set { this.mRemoveAllOptions = value; } }
36+
37+
/* Functions */
38+
39+
private void Awake()
40+
{
41+
this.mDropdown = GetComponent<TMP_Dropdown>();
42+
43+
Refresh();
44+
45+
AddListener();
46+
}
47+
48+
private void AddListener()
49+
{
50+
mDropdown.onValueChanged.AddListener(delegate
51+
{
52+
OnValueChanged(mDropdown);
53+
});
54+
55+
// Run once.
56+
OnValueChanged(mDropdown);
57+
}
58+
59+
/// <summary>
60+
/// Refresh all options once.
61+
/// </summary>
62+
public void Refresh()
63+
{
64+
if (mRemoveAllOptions)
65+
mDropdown.ClearOptions();
66+
67+
foreach (string resolution in mResolutions)
68+
{
69+
JCS_UIUtil.Dropdown_AddOption(mDropdown, resolution);
70+
}
71+
72+
// Default to the current screen resolution.
73+
{
74+
string res = Screen.width + "x" + Screen.height;
75+
76+
JCS_UIUtil.Dropdown_SetSelection(mDropdown, res);
77+
}
78+
}
79+
80+
private void OnValueChanged(TMP_Dropdown dropdown)
81+
{
82+
string text = JCS_UIUtil.Dropdown_GetSelectedValue(dropdown);
83+
84+
string[] data = text.Split("x");
85+
86+
Resolution res = Screen.currentResolution;
87+
88+
int width = JCS_Util.Parse(data[0], res.width);
89+
int height = JCS_Util.Parse(data[1], res.height);
90+
91+
Screen.SetResolution(width, height, Screen.fullScreenMode);
92+
93+
#if UNITY_EDITOR
94+
GameViewUtils.AddAndSelectCustomSize(
95+
GameViewUtils.GameViewSizeType.FixedResolution,
96+
GameViewSizeGroupType.Standalone, width, height,
97+
text);
98+
#endif
99+
}
100+
}
101+
}
File renamed without changes.

Assets/JCSUnity/Scripts/UI/Dropdown/JCS_DropdownScreenResolutions.cs

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using System.Collections.Generic;
2+
using UnityEngine;
3+
using TMPro;
4+
using MyBox;
5+
using UnityEditor;
6+
7+
namespace JCSUnity
8+
{
9+
/// <summary>
10+
/// A dropdown menu let you choose the windowed mode.
11+
/// </summary>
12+
[RequireComponent(typeof(TMP_Dropdown))]
13+
public class JCS_DropdownWindowedMode : MonoBehaviour
14+
{
15+
/* Variables */
16+
17+
private TMP_Dropdown mDropdown = null;
18+
19+
[Separator("Initialize Variables (JCS_DropdownWindowedMode)")]
20+
21+
[Tooltip("A list of windowed option to use.")]
22+
[SerializeField]
23+
[ReadOnly]
24+
private List<string> mOptions = new List<string>()
25+
{
26+
"Full Screen",
27+
"Windowed",
28+
};
29+
30+
[Tooltip("If true, remove all other options at the beginning.")]
31+
[SerializeField]
32+
private bool mRemoveAllOptions = true;
33+
34+
/* Setter & Getter */
35+
36+
public List<string> Options { get { return mOptions; } set { this.mOptions = value; } }
37+
public bool RemoveAllOptions { get { return mRemoveAllOptions; } set { this.mRemoveAllOptions = value; } }
38+
39+
/* Functions */
40+
41+
private void Awake()
42+
{
43+
this.mDropdown = GetComponent<TMP_Dropdown>();
44+
45+
Refresh();
46+
47+
AddListener();
48+
}
49+
50+
private void AddListener()
51+
{
52+
mDropdown.onValueChanged.AddListener(delegate
53+
{
54+
OnValueChanged(mDropdown);
55+
});
56+
57+
// Run once.
58+
OnValueChanged(mDropdown);
59+
}
60+
61+
/// <summary>
62+
/// Refresh all options once.
63+
/// </summary>
64+
public void Refresh()
65+
{
66+
if (mRemoveAllOptions)
67+
mDropdown.ClearOptions();
68+
69+
foreach (string option in mOptions)
70+
{
71+
JCS_UIUtil.Dropdown_AddOption(mDropdown, option);
72+
}
73+
74+
// Default to the current windowed mode.
75+
{
76+
string text = ModeToString(Screen.fullScreenMode);
77+
78+
JCS_UIUtil.Dropdown_SetSelection(mDropdown, text);
79+
}
80+
}
81+
82+
private void OnValueChanged(TMP_Dropdown dropdown)
83+
{
84+
string text = JCS_UIUtil.Dropdown_GetSelectedValue(dropdown);
85+
86+
FullScreenMode mode = StringToMode(text);
87+
88+
Resolution res = Screen.currentResolution;
89+
90+
int width = res.width;
91+
int height = res.height;
92+
93+
Screen.SetResolution(width, height, mode);
94+
}
95+
96+
private string ModeToString(FullScreenMode mode)
97+
{
98+
switch (mode)
99+
{
100+
case FullScreenMode.FullScreenWindow:
101+
return "Full Screen";
102+
case FullScreenMode.Windowed:
103+
return "Windowed";
104+
}
105+
106+
return JCS_UIUtil.Dropdown_GetSelectedValue(mDropdown);
107+
}
108+
109+
private FullScreenMode StringToMode(string text)
110+
{
111+
switch (text)
112+
{
113+
case "Full Screen":
114+
return FullScreenMode.FullScreenWindow;
115+
case "Windowed":
116+
return FullScreenMode.Windowed;
117+
}
118+
119+
return Screen.fullScreenMode;
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)