Repository: PixeyeHQ/InspectorFoldoutGroup
Branch: master
Commit: 8f6fbe7724a9
Files: 7
Total size: 20.0 KB
Directory structure:
gitextract_ia10q94b/
├── .gitignore
├── Homebrew/
│ └── DecorateFoldout/
│ ├── Attributes/
│ │ └── FoldAttribute.cs
│ └── Editor/
│ ├── EditorOverride.cs
│ └── Resources/
│ ├── IN foldout focus on-5718.png.meta
│ └── IN foldout focus-6510.png.meta
├── LICENSE
└── README.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
[Ll]ibrary/
[Tt]emp/
[Oo]bj/
[Bb]uild/
[Bb]uilds/
Assets/AssetStoreTools*
# Visual Studio cache directory
.vs/
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.opendb
# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
# Unity3D Generated File On Crash Reports
sysinfo.txt
# Builds
*.apk
*.unitypackage
================================================
FILE: Homebrew/DecorateFoldout/Attributes/FoldAttribute.cs
================================================
// Project : UNITY FOLDOUT
// Contacts : Pix - ask@pixeye.games
using UnityEngine;
namespace Pixeye.Unity
{
public class FoldoutAttribute : PropertyAttribute
{
public string name;
public bool foldEverything;
/// Adds the property to the specified foldout group.
/// Name of the foldout group.
/// Toggle to put all properties to the specified group
public FoldoutAttribute(string name, bool foldEverything = false)
{
this.foldEverything = foldEverything;
this.name = name;
}
}
}
================================================
FILE: Homebrew/DecorateFoldout/Editor/EditorOverride.cs
================================================
// Project : UNITY FOLDOUT
// Contacts : Pix - ask@pixeye.games
using Homebrew;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Pixeye.Unity
{
[CustomEditor(typeof(Object), true, isFallback = true)]
[CanEditMultipleObjects]
public class EditorOverride : Editor
{
//===============================//
// Members
//===============================//
Dictionary cacheFolds = new Dictionary();
List props = new List();
List methods = new List();
bool initialized;
//===============================//
// Logic
//===============================//
void OnEnable()
{
initialized = false;
}
void OnDisable()
{
//if (Application.wantsToQuit)
//if (applicationIsQuitting) return;
// if (Toolbox.isQuittingOrChangingScene()) return;
if (target != null)
foreach (var c in cacheFolds)
{
EditorPrefs.SetBool(string.Format($"{c.Value.atr.name}{c.Value.props[0].name}{target.GetInstanceID()}"), c.Value.expanded);
c.Value.Dispose();
}
}
public override bool RequiresConstantRepaint()
{
return EditorFramework.needToRepaint;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
Setup();
if (props.Count == 0)
{
DrawDefaultInspector();
return;
}
Header();
Body();
serializedObject.ApplyModifiedProperties();
void Header()
{
using (new EditorGUI.DisabledScope("m_Script" == props[0].propertyPath))
{
EditorGUILayout.Space();
EditorGUILayout.PropertyField(props[0], true);
EditorGUILayout.Space();
}
}
void Body()
{
foreach (var pair in cacheFolds)
{
this.UseVerticalLayout(() => Foldout(pair.Value), StyleFramework.box);
EditorGUI.indentLevel = 0;
}
EditorGUILayout.Space();
for (var i = 1; i < props.Count; i++)
{
// if (props[i].isArray)
// {
// DrawPropertySortableArray(props[i]);
// }
// else
// {
EditorGUILayout.PropertyField(props[i], true);
//}
}
EditorGUILayout.Space();
if (methods == null) return;
foreach (MethodInfo memberInfo in methods)
{
this.UseButton(memberInfo);
}
}
void Foldout(CacheFoldProp cache)
{
cache.expanded = EditorGUILayout.Foldout(cache.expanded, cache.atr.name, true,
StyleFramework.foldout);
if (cache.expanded)
{
EditorGUI.indentLevel = 1;
for (int i = 0; i < cache.props.Count; i++)
{
this.UseVerticalLayout(() => Child(i), StyleFramework.boxChild);
}
}
void Child(int i)
{
// if (cache.props[i].isArray)
// {
// DrawPropertySortableArray(cache.props[i]);
// }
// else
// {
EditorGUILayout.PropertyField(cache.props[i], new GUIContent(ObjectNames.NicifyVariableName(cache.props[i].name)), true);
//}
}
}
void Setup()
{
EditorFramework.currentEvent = Event.current;
if (!initialized)
{
// SetupButtons();
List objectFields;
FoldoutAttribute prevFold = default;
var length = EditorTypes.Get(target, out objectFields);
for (var i = 0; i < length; i++)
{
#region FOLDERS
var fold = Attribute.GetCustomAttribute(objectFields[i], typeof(FoldoutAttribute)) as FoldoutAttribute;
CacheFoldProp c;
if (fold == null)
{
if (prevFold != null && prevFold.foldEverything)
{
if (!cacheFolds.TryGetValue(prevFold.name, out c))
{
cacheFolds.Add(prevFold.name, new CacheFoldProp {atr = prevFold, types = new HashSet {objectFields[i].Name}});
}
else
{
c.types.Add(objectFields[i].Name);
}
}
continue;
}
prevFold = fold;
if (!cacheFolds.TryGetValue(fold.name, out c))
{
var expanded = EditorPrefs.GetBool(string.Format($"{fold.name}{objectFields[i].Name}{target.GetInstanceID()}"), false);
cacheFolds.Add(fold.name, new CacheFoldProp {atr = fold, types = new HashSet {objectFields[i].Name}, expanded = expanded});
}
else c.types.Add(objectFields[i].Name);
#endregion
}
var property = serializedObject.GetIterator();
var next = property.NextVisible(true);
if (next)
{
do
{
HandleFoldProp(property);
} while (property.NextVisible(false));
}
initialized = true;
}
}
// void SetupButtons()
// {
// var members = GetButtonMembers(target);
//
// foreach (var memberInfo in members)
// {
// var method = memberInfo as MethodInfo;
// if (method == null)
// {
// continue;
// }
//
// if (method.GetParameters().Length > 0)
// {
// continue;
// }
//
// if (methods == null) methods = new List();
// methods.Add(method);
// }
// }
}
public void HandleFoldProp(SerializedProperty prop)
{
bool shouldBeFolded = false;
foreach (var pair in cacheFolds)
{
if (pair.Value.types.Contains(prop.name))
{
var pr = prop.Copy();
shouldBeFolded = true;
pair.Value.props.Add(pr);
break;
}
}
if (shouldBeFolded == false)
{
var pr = prop.Copy();
props.Add(pr);
}
}
// IEnumerable GetButtonMembers(object target)
// {
// return target.GetType()
// .GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic)
// .Where(CheckButtonAttribute);
// }
// bool CheckButtonAttribute(MemberInfo memberInfo)
// {
// return Attribute.IsDefined(memberInfo, typeof(ButtonAttribute));
// }
class CacheFoldProp
{
public HashSet types = new HashSet();
public List props = new List();
public FoldoutAttribute atr;
public bool expanded;
public void Dispose()
{
props.Clear();
types.Clear();
atr = null;
}
}
}
static class ditorUIHelper
{
public static void UseVerticalLayout(this Editor e, Action action, GUIStyle style)
{
EditorGUILayout.BeginVertical(style);
action();
EditorGUILayout.EndVertical();
}
public static void UseButton(this Editor e, MethodInfo m)
{
if (GUILayout.Button(m.Name))
{
m.Invoke(e.target, null);
}
}
}
static class StyleFramework
{
public static GUIStyle box;
public static GUIStyle boxChild;
public static GUIStyle foldout;
public static GUIStyle button;
public static GUIStyle text;
static StyleFramework()
{
bool pro = EditorGUIUtility.isProSkin;
var uiTex_in = Resources.Load("IN foldout focus-6510");
var uiTex_in_on = Resources.Load("IN foldout focus on-5718");
var c_on = pro ? Color.white : new Color(51 / 255f, 102 / 255f, 204 / 255f, 1);
button = new GUIStyle(EditorStyles.miniButton);
button.font = Font.CreateDynamicFontFromOSFont(new[] {"Terminus (TTF) for Windows", "Calibri"}, 17);
text = new GUIStyle(EditorStyles.label);
text.richText = true;
text.contentOffset = new Vector2(0, 5);
text.font = Font.CreateDynamicFontFromOSFont(new[] {"Terminus (TTF) for Windows", "Calibri"}, 14);
foldout = new GUIStyle(EditorStyles.foldout);
foldout.overflow = new RectOffset(-10, 0, 3, 0);
foldout.padding = new RectOffset(25, 0, -3, 0);
foldout.active.textColor = c_on;
foldout.active.background = uiTex_in;
foldout.onActive.textColor = c_on;
foldout.onActive.background = uiTex_in_on;
foldout.focused.textColor = c_on;
foldout.focused.background = uiTex_in;
foldout.onFocused.textColor = c_on;
foldout.onFocused.background = uiTex_in_on;
foldout.hover.textColor = c_on;
foldout.hover.background = uiTex_in;
foldout.onHover.textColor = c_on;
foldout.onHover.background = uiTex_in_on;
box = new GUIStyle(GUI.skin.box);
box.padding = new RectOffset(10, 0, 10, 0);
boxChild = new GUIStyle(GUI.skin.box);
boxChild.active.textColor = c_on;
boxChild.active.background = uiTex_in;
boxChild.onActive.textColor = c_on;
boxChild.onActive.background = uiTex_in_on;
boxChild.focused.textColor = c_on;
boxChild.focused.background = uiTex_in;
boxChild.onFocused.textColor = c_on;
boxChild.onFocused.background = uiTex_in_on;
EditorStyles.foldout.active.textColor = c_on;
EditorStyles.foldout.active.background = uiTex_in;
EditorStyles.foldout.onActive.textColor = c_on;
EditorStyles.foldout.onActive.background = uiTex_in_on;
EditorStyles.foldout.focused.textColor = c_on;
EditorStyles.foldout.focused.background = uiTex_in;
EditorStyles.foldout.onFocused.textColor = c_on;
EditorStyles.foldout.onFocused.background = uiTex_in_on;
EditorStyles.foldout.hover.textColor = c_on;
EditorStyles.foldout.hover.background = uiTex_in;
EditorStyles.foldout.onHover.textColor = c_on;
EditorStyles.foldout.onHover.background = uiTex_in_on;
}
public static string FirstLetterToUpperCase(this string s)
{
if (string.IsNullOrEmpty(s))
return string.Empty;
var a = s.ToCharArray();
a[0] = char.ToUpper(a[0]);
return new string(a);
}
public static IList GetTypeTree(this Type t)
{
var types = new List();
while (t.BaseType != null)
{
types.Add(t);
t = t.BaseType;
}
return types;
}
}
static class EditorTypes
{
public static Dictionary> fields = new Dictionary>(FastComparable.Default);
public static int Get(Object target, out List objectFields)
{
var t = target.GetType();
var hash = t.GetHashCode();
if (!fields.TryGetValue(hash, out objectFields))
{
var typeTree = t.GetTypeTree();
objectFields = target.GetType()
.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic)
.OrderByDescending(x => typeTree.IndexOf(x.DeclaringType))
.ToList();
fields.Add(hash, objectFields);
}
return objectFields.Count;
}
}
class FastComparable : IEqualityComparer
{
public static FastComparable Default = new FastComparable();
public bool Equals(int x, int y)
{
return x == y;
}
public int GetHashCode(int obj)
{
return obj.GetHashCode();
}
}
[InitializeOnLoad]
public static class EditorFramework
{
internal static bool needToRepaint;
internal static Event currentEvent;
internal static float t;
static EditorFramework()
{
EditorApplication.update += Updating;
}
static void Updating()
{
CheckMouse();
if (needToRepaint)
{
t += Time.deltaTime;
if (t >= 0.3f)
{
t -= 0.3f;
needToRepaint = false;
}
}
}
static void CheckMouse()
{
var ev = currentEvent;
if (ev == null) return;
if (ev.type == EventType.MouseMove)
needToRepaint = true;
}
}
}
================================================
FILE: Homebrew/DecorateFoldout/Editor/Resources/IN foldout focus on-5718.png.meta
================================================
fileFormatVersion: 2
guid: 07896d08487bbb049b494e9e216360ad
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 5
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: -1
mipBias: -1
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Homebrew/DecorateFoldout/Editor/Resources/IN foldout focus-6510.png.meta
================================================
fileFormatVersion: 2
guid: 795626f49ade9024a86e0c1a58aa004b
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 5
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: -1
mipBias: -1
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018 Dimitry
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
[](https://github.com/dimmpixeye/InspectorFoldoutGroup/blob/master/LICENSE)
[](https://discord.gg/ukhzx83)
# InspectorFoldoutGroup
Group variables in Unity 3d inspector with style!
[](https://gyazo.com/9f18eab9dfb123d928aecf7daa3e01da)
[](https://gyazo.com/4e6566c2fca783e4cd557f95713a4ab5)
## How to use
Put attribute before variable and you are done !
```csharp
[Foldout("DESIRED_NAME")]
```
```csharp
public class Player : MonoBehaviour
{
[Foldout("Setup")] public Transform selfTransform;
[Foldout("Data")] public int HP;
[Foldout("Data")] public int AT;
}
```
You don't need to write [Foldout] attribute each time! Instead, you can add "true" bool check afther naming to put all properties to the specified group
```csharp
public class Player : MonoBehaviour
{
[Foldout("DATA OBJECT", true)]
public int hp;
public int attack = 20;
[SerializeField]
private GameObject self;
[Foldout("DATA ATTACK")]
public int AT;
}
```
[](https://gyazo.com/2ce500e63fd604de8098aece2fa354fa)
## Other content
* [Tag filters](https://github.com/dimmpixeye/Unity3d-Tags-Filters) - an extension to add foldable groups to the inspector.
* [ACTORS](https://github.com/dimmpixeye/Actors-Unity3d-Framework) - Unity3d data-driven framework I'm currently working on.