Last active
January 14, 2025 11:53
-
-
Save BennyKok/f0fdaf68d3074b72562632a0c3d4b193 to your computer and use it in GitHub Desktop.
more details here -> https://blog.bennykok.com/posts/better-custom-foldout-in-unity
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//visible[0] is an AnimBool, you can cache it somewhere in your custom editor. | |
using (new EditorUtils.FoldoutScope(visible[0], out var shouldDraw, "SongItem")) | |
{ | |
if (shouldDraw) | |
{ | |
//draw the rest of your GUI. | |
songItem = EditorGUILayout.ObjectField(songItem, typeof(SongItem), false) as SongItem; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defaultFoldout = EditorGUILayout.Foldout(defaultFoldout, "Default Foldout", true); | |
if (defaultFoldout) | |
{ | |
EditorGUILayout.TextField("Dummy Data", ""); | |
EditorGUILayout.TextField("Dummy Data", ""); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using UnityEditor; | |
using UnityEditor.AnimatedValues; | |
using UnityEngine; | |
namespace RhythmGameStarter | |
{ | |
public static class EditorUtils | |
{ | |
public readonly struct FoldoutScope : IDisposable | |
{ | |
private readonly bool wasIndent; | |
public FoldoutScope(AnimBool value, out bool shouldDraw, string label, bool indent = true, SerializedProperty toggle = null) | |
{ | |
value.target = Foldout(value.target, label, toggle); | |
shouldDraw = EditorGUILayout.BeginFadeGroup(value.faded); | |
if (shouldDraw && indent) | |
{ | |
Indent(); | |
wasIndent = true; | |
} | |
else | |
{ | |
wasIndent = false; | |
} | |
} | |
public void Dispose() | |
{ | |
if (wasIndent) | |
EndIndent(); | |
EditorGUILayout.EndFadeGroup(); | |
} | |
} | |
public static void HorizontalLine(float height = 1, float width = -1, Vector2 margin = new Vector2()) | |
{ | |
GUILayout.Space(margin.x); | |
var rect = EditorGUILayout.GetControlRect(false, height); | |
if (width > -1) | |
{ | |
var centerX = rect.width / 2; | |
rect.width = width; | |
rect.x += centerX - width / 2; | |
} | |
Color color = EditorStyles.label.active.textColor; | |
color.a = 0.5f; | |
EditorGUI.DrawRect(rect, color); | |
GUILayout.Space(margin.y); | |
} | |
public static bool Foldout(bool value, string label, SerializedProperty toggle = null) | |
{ | |
bool _value; | |
EditorGUILayout.BeginVertical(EditorStyles.helpBox); | |
EditorGUILayout.BeginHorizontal(); | |
if (toggle != null && !toggle.boolValue) | |
{ | |
EditorGUI.BeginDisabledGroup(true); | |
_value = EditorGUILayout.Toggle(value, EditorStyles.foldout); | |
EditorGUI.EndDisabledGroup(); | |
_value = false; | |
} | |
else | |
{ | |
_value = EditorGUILayout.Toggle(value, EditorStyles.foldout); | |
} | |
if (toggle != null) | |
{ | |
EditorGUI.BeginChangeCheck(); | |
EditorGUILayout.PropertyField(toggle, GUIContent.none, GUILayout.Width(20)); | |
if (EditorGUI.EndChangeCheck() && toggle.boolValue) | |
_value = true; | |
} | |
EditorGUILayout.EndHorizontal(); | |
EditorGUILayout.EndVertical(); | |
var rect = GUILayoutUtility.GetLastRect(); | |
rect.x += 20; | |
rect.width -= 20; | |
if (toggle != null && !toggle.boolValue) | |
{ | |
EditorGUI.BeginDisabledGroup(true); | |
EditorGUI.LabelField(rect, label, EditorStyles.boldLabel); | |
EditorGUI.EndDisabledGroup(); | |
} | |
else | |
{ | |
EditorGUI.LabelField(rect, label, EditorStyles.boldLabel); | |
} | |
return _value; | |
} | |
public static void Indent() | |
{ | |
EditorGUILayout.BeginHorizontal(); | |
GUILayout.Space(16); | |
EditorGUILayout.BeginVertical(); | |
} | |
public static void EndIndent() | |
{ | |
GUILayout.Space(16); | |
EditorGUILayout.EndVertical(); | |
EditorGUILayout.EndHorizontal(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public FoldoutScope(AnimBool value, out bool shouldDraw, string label, bool indent = true, SerializedProperty toggle = null) | |
{ | |
value.target = Foldout(value.target, label, toggle); | |
shouldDraw = EditorGUILayout.BeginFadeGroup(value.faded); | |
if (shouldDraw && indent) | |
{ | |
Indent(); | |
wasIndent = true; | |
} | |
else | |
{ | |
wasIndent = false; | |
} | |
} |
It would be a bit tricky to use in the property drawer. do you plan to do a custom editor for the Scriptable Object as well? or no?
@BennyKok I managed to do it. The logic for drawing sub-properties of scriptable objects was in the property drawer, however I completely restructured it and now everything is drawn in the editor.
Thanks for the response and for the code 🙌
Thats great to hear!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey, @BennyKok
Thanks you very much for this code, I've been struggling with it for weeks and finally found a proper foldout.
It works perfectly in the Editor subclass, however I'm having problems in property drawer. If you look at the image the Ads foldout is drawn in a custom editor, however everything underneath is drawn in a property drawer.
Is it possible to use this foldout in property drawers too? Specifically for the 'Settings' foldout in the image. If so, do you have code for that?
Thanks in advance