Skip to content

Instantly share code, notes, and snippets.

@Diman119
Last active October 18, 2024 09:49
Show Gist options
  • Save Diman119/223fbaf376d88a8adc234d095c040ce4 to your computer and use it in GitHub Desktop.
Save Diman119/223fbaf376d88a8adc234d095c040ce4 to your computer and use it in GitHub Desktop.

Script for tuning font sizes of Unity Editor UI

Useful for increasing font sizes on MacOs / Linux, where UI scale option is unavailable

Based on this script by nukadelic: https://gist.github.com/nukadelic/47474c7e5d4ee5909462e3b900f4cb82

Put the script anywhere in the Assets folder, then go to Window > Editor Font Resizer

Features:

  • change font sizes of any style individually
  • global size setting
  • set text alignment to middle to prevent scaled text from being cut off
  • save / load your configuration to file (file path can be set in the script)
  • auto restore configuration on startup or whenever Unity resets it (such as when entering play mode)

For automatic configuration restoration window of Editor Font Resizer needs to be visible

With the latest update global zoom can be safely set up to 18 (the default is 10) and if you need more, consider using the GDK_SCALE=2 environment variable for scaling instead, which would yield an effective zoom of 20

#if UNITY_EDITOR
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Reflection;
using System.IO;
using System.Text;
public class EditorFontResizer : EditorWindow {
[MenuItem("Window/Editor Font Resizer")]
static void Open() => GetWindow<EditorFontResizer>("Editor Font Resizer").minSize = new Vector2(180f, 10f);
const string _configPath = "EditorFontResizer.cfg";
static Dictionary<string, int> _config;
class StyleInfo {
public string name;
GUIStyle _style;
public int FontSize {
get => _config[name];
set {
if (value > 0) {
_config[name] = _style.fontSize = value;
}
}
}
public StyleInfo(string _name, GUIStyle __style) {
name = _name;
_style = __style;
InitSize(_style);
InitAlignment(_style);
// Uncomment to disable text being cut off when it does not fit (not recommended)
// InitClipping(_style);
}
void InitSize(GUIStyle style) {
if (style.fontSize == 0) {
style.fontSize = GUI.skin.font.fontSize;
}
if (_config.ContainsKey(name)) {
style.fontSize = _config[name];
} else {
_config.Add(name, style.fontSize);
}
}
void InitAlignment(GUIStyle style) {
if (!style.wordWrap) {
switch (style.alignment) {
case TextAnchor.LowerLeft: case TextAnchor.UpperLeft:
style.alignment = TextAnchor.MiddleLeft;
break;
case TextAnchor.LowerRight: case TextAnchor.UpperRight:
style.alignment = TextAnchor.MiddleRight;
break;
case TextAnchor.LowerCenter: case TextAnchor.UpperCenter:
style.alignment = TextAnchor.MiddleCenter;
break;
}
}
}
void InitClipping(GUIStyle style) {
style.clipping = TextClipping.Overflow;
}
}
List<StyleInfo> _editorStyles;
List<StyleInfo> _guiStyles;
List<StyleInfo> _customStyles;
Dictionary<string, bool> _foldouts = new Dictionary<string, bool>();
GUIStyle _evenBG;
GUIStyle _oddBG;
Vector2 _scroll;
void InitStyles() {
if (_evenBG != null) {
return;
}
GUIStyle s = "CN EntryBackEven";
_evenBG = new GUIStyle(s);
s = "CN EntryBackOdd";
_oddBG = new GUIStyle(s);
_evenBG.contentOffset = _oddBG.contentOffset = Vector2.zero;
_evenBG.clipping = _oddBG.clipping = TextClipping.Clip;
_evenBG.margin = _oddBG.margin =
_evenBG.padding = _oddBG.padding = new RectOffset();
}
GUIStyle TryGetGUIStyle(PropertyInfo x, object item) {
if (string.IsNullOrEmpty(x.Name) || x.PropertyType != typeof(GUIStyle)) {
return null;
}
return (GUIStyle) x.GetValue(item, null);
}
bool ValidFontStyle(GUIStyle s) {
return s != null && !string.IsNullOrEmpty(s.name);
}
Dictionary<string, int> ReadDictionary(string path) {
Dictionary<string, int> dict = new Dictionary<string, int>();
FileInfo fileInfo = new FileInfo(path);
if (fileInfo.Exists) {
using (FileStream fileStream = fileInfo.OpenRead()) {
using (StreamReader reader = new StreamReader(fileStream, Encoding.UTF8)) {
while (!reader.EndOfStream) {
string[] pair = reader.ReadLine().Split(':');
dict[pair[0]] = int.Parse(pair[1]);
}
}
}
}
return dict;
}
void WriteDictionary(Dictionary<string, int> dict, string path) {
using (StreamWriter file = new StreamWriter(path)) {
foreach (var pair in dict) {
file.WriteLine("{0}:{1}", pair.Key, pair.Value);
}
}
}
void InitProperties() {
if (_editorStyles != null && _guiStyles != null && _customStyles != null) {
return;
}
var trackedStyles = new HashSet<GUIStyle>();
_config = ReadDictionary(_configPath);
_editorStyles = new List<StyleInfo>();
var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty;
foreach (var x in typeof(EditorStyles).GetProperties(flags)) {
var s = TryGetGUIStyle(x, null);
if (s == null || trackedStyles.Contains(s)) {
continue;
}
trackedStyles.Add(s);
_editorStyles.Add(new StyleInfo("editor." + x.Name, s));
}
_guiStyles = new List<StyleInfo>();
foreach (var x in GUI.skin.GetType().GetProperties()) {
var s = TryGetGUIStyle(x, GUI.skin);
if (s == null || trackedStyles.Contains(s)) {
continue;
}
trackedStyles.Add(s);
_guiStyles.Add(new StyleInfo("gui." + x.Name, s));
}
_customStyles = new List<StyleInfo>();
foreach (var s in GUI.skin.customStyles) {
if (!ValidFontStyle(s) || trackedStyles.Contains(s)) {
continue;
}
trackedStyles.Add(s);
_customStyles.Add(new StyleInfo("custom." + s.name, s));
}
ApplyChanges();
}
void RepaintAllWindows() {
foreach (var w in Resources.FindObjectsOfTypeAll<EditorWindow>()) {
w.Repaint();
}
}
void ApplyChanges() {
WriteDictionary(_config, _configPath);
RepaintAllWindows();
}
bool Header(string name) {
if (!_foldouts.ContainsKey(name)) {
_foldouts.Add(name, true);
}
GUILayout.Space(5);
var foldout = EditorGUILayout.Foldout(!_foldouts[name], name, true);
_foldouts[name] = !foldout;
return foldout;
}
void FontSizeRow(StyleInfo styleInfo, bool even) {
int delta = FontSizeRow(styleInfo.name, styleInfo.FontSize.ToString(), even ? _evenBG : _oddBG);
if (delta != 0) {
styleInfo.FontSize += delta;
ApplyChanges();
}
}
int FontSizeRow(string name, string size, GUIStyle style) {
var width = GUILayout.MaxWidth(Screen.width);
using (new GUILayout.HorizontalScope(style, width)) {
GUILayout.Label(name);
GUILayout.FlexibleSpace();
if (GUILayout.Button("-", EditorStyles.miniButtonLeft)) {
return -1;
}
using (new EditorGUI.DisabledGroupScope(true)) {
GUILayout.Label(size, EditorStyles.miniButtonMid, GUILayout.Width(30));
}
if (GUILayout.Button("+", EditorStyles.miniButtonRight)) {
return 1;
}
}
return 0;
}
void OnGUI() {
InitStyles();
// GUILayout.Label("Editor Font Resizer", EditorStyles.boldLabel, GUILayout.MaxWidth(Screen.width));
int rowCount = 0;
using (var scope = new GUILayout.ScrollViewScope(_scroll)) {
_scroll = scope.scrollPosition;
if (GUILayout.Button("Reload Config", EditorStyles.miniButtonMid)) {
_editorStyles = _guiStyles = _customStyles = null;
}
InitProperties();
int delta = FontSizeRow("Global Zoom", _config["editor.miniLabel"].ToString(), _oddBG);
if (delta != 0) {
foreach (var style in _editorStyles) {
style.FontSize += delta;
}
foreach (var style in _guiStyles) {
style.FontSize += delta;
}
foreach (var style in _customStyles) {
style.FontSize += delta;
}
ApplyChanges();
}
if (Header("Editor Styles")) {
foreach (var style in _editorStyles) {
FontSizeRow(style, rowCount % 2 == 0);
++rowCount;
}
}
if (Header("GUI Skins")) {
foreach (var style in _guiStyles) {
FontSizeRow(style, rowCount % 2 == 0);
++rowCount;
}
}
if (Header("Custom Styles")) {
foreach (var style in _customStyles) {
FontSizeRow(style, rowCount % 2 == 0);
++rowCount;
}
}
}
}
}
#endif
@nukadelic
Copy link

Appreciate the reference

@TheSunCat
Copy link

Thanks for this script! Is there any way to make the changes stick even if the resizer window is not open, or is this a hard requirement due to how Unity works?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment