Skip to content

Commit

Permalink
feat: 配列表示以外の全てのObjectFieldでのコンポーネントインデックス表示に対応
Browse files Browse the repository at this point in the history
  • Loading branch information
pspkurara committed Nov 6, 2020
1 parent 84b7c66 commit 66b737c
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Packages/uGUI-Skinner/Editor/EditorConst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static class EditorConst
public static readonly GUILayoutOption SkinSelectArrowMaxWidth = GUILayout.MaxWidth(50);
public static readonly GUILayoutOption SkinAddOrRemoveButtonMaxWidth = GUILayout.MaxWidth(150);

public static readonly GUILayoutOption ComponentIndexFieldMaxWidth = GUILayout.MaxWidth(50);
public const float ComponentIndexFieldWidth = 50;

public static readonly GUILayoutOption[] LineBoxStyle = new GUILayoutOption[] { GUILayout.Height(1), GUILayout.ExpandWidth(true) };

Expand Down
33 changes: 6 additions & 27 deletions Packages/uGUI-Skinner/Editor/SkinPartsOnArrayInspector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,45 +33,22 @@ public void DrawInspector(EditorSkinPartsPropertry property)
SkinnerEditorUtility.ResetArray(property.objectReferenceValues, DefaultArrayLength, false);
ResetArrayOtherThanObjectReference(property);

var componentInfo = SkinnerEditorUtility.GetComponentInfos(typeof(T));

int indent = EditorGUI.indentLevel;

for (int iz = 0; iz < property.objectReferenceValues.arraySize; iz++)
{
EditorGUILayout.BeginHorizontal();
SerializedProperty gameObjectProperty = property.objectReferenceValues.GetArrayElementAtIndex(iz);
m_FieldNumberTitle.text = string.Format(EditorConst.FieldNumberTitle, iz);
SkinnerEditorGUILayout.ObjectField(m_FieldNumberTitle, gameObjectProperty, typeof(T));
if (componentInfo.isComponent && componentInfo.allowMultiplyComponent)
{
T c = gameObjectProperty.objectReferenceValue as T;
int componentIndex = -1;
List<T> componentList = null;
if (c)
{
componentList = (c as Component).gameObject.GetComponents<T>().ToList();
componentIndex = componentList.IndexOf(c);
}
bool guiEnabled = GUI.enabled;
if (componentIndex < 0)
{
componentIndex = 0;
GUI.enabled = false;
}
int editIndex = EditorGUILayout.IntField(GUIContent.none, componentIndex, EditorConst.ComponentIndexFieldMaxWidth);
if (editIndex != componentIndex)
{
editIndex = Mathf.Clamp(editIndex, 0, componentList.Count - 1);
gameObjectProperty.objectReferenceValue = componentList[editIndex];
gameObjectProperty.serializedObject.ApplyModifiedProperties();
}
GUI.enabled = guiEnabled;
}

EditorGUI.indentLevel = 0;
if (SkinnerEditorUtility.DrawRemoveButton(EditorConst.RemoveFieldButtonTitle, () => {
property.objectReferenceValues.GetArrayElementAtIndex(iz).objectReferenceValue = null;
property.objectReferenceValues.DeleteArrayElementAtIndex(iz);
property.objectReferenceValues.serializedObject.ApplyModifiedProperties();
})) return;
EditorGUI.indentLevel = indent;
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.BeginHorizontal();
Expand All @@ -82,10 +59,12 @@ public void DrawInspector(EditorSkinPartsPropertry property)

m_AddFieldButtonTitle.text = string.Format(EditorConst.AddFieldButtonTitle, displayObjectTypeName);

EditorGUI.indentLevel = 0;
bool isClicked = SkinnerEditorUtility.DrawAddButton(m_AddFieldButtonTitle, () => {
property.objectReferenceValues.InsertArrayElementAtIndex(property.objectReferenceValues.arraySize);
property.objectReferenceValues.serializedObject.ApplyModifiedProperties();
});
EditorGUI.indentLevel = indent;

if (isClicked) return;
EditorGUILayout.EndHorizontal();
Expand Down
65 changes: 63 additions & 2 deletions Packages/uGUI-Skinner/Editor/SkinnerEditorGUILayout.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using Array = System.Array;

namespace Pspkurara.UI.Skinner
{
Expand All @@ -14,6 +16,7 @@ public static class SkinnerEditorGUILayout

/// <summary>
/// <see cref="EditorGUILayout.ObjectField"/>を表示
/// 重複アタッチ可能なコンポーネントの場合はアタッチ順を元に切り替え可能な<see cref="EditorGUILayout.IntField"/>を併せて描画
/// </summary>
/// <param name="label">ラベル</param>
/// <param name="property">プロパティ</param>
Expand All @@ -26,9 +29,67 @@ public static void ObjectField(GUIContent label, SerializedProperty property, Sy
{
EditorGUI.showMixedValue = true;
}
bool isComponent = type == typeof(Component) || type.IsSubclassOf(typeof(Component));

// コンポーネントの情報を確認し、複数アタッチできるかチェック
bool isGameObject = type == typeof(GameObject);
var result = EditorGUILayout.ObjectField(label, property.objectReferenceValue, type, isComponent || isGameObject, options);
var componentInfo = SkinnerEditorUtility.GetComponentInfos(type);
bool showComponentIndex = componentInfo.isComponent && componentInfo.allowMultiplyComponent;

var rect = EditorGUILayout.GetControlRect(options);

var objectFieldRect = rect;

// コンポーネントインデックス表示の場合はオブジェクトフィールドがその分縮む
if (showComponentIndex)
{
objectFieldRect.width -= EditorConst.ComponentIndexFieldWidth + EditorGUIUtility.standardVerticalSpacing;
}

var result = EditorGUI.ObjectField(objectFieldRect, label, property.objectReferenceValue, type, componentInfo.isComponent || isGameObject);

// コンポーネントインデックス表示が有効
if (showComponentIndex)
{
// 1度キャストして本当にコンポーネントがアタッチされているか検証
Component castedResult = result as Component;
int componentIndex = -1;
Component[] componentList = null;
// null以外 & 指定された型の継承クラスかを調べる
if (result != null && (result.GetType() == type || type.IsSubclassOf(result.GetType())))
{
// 同じオブジェクトから全ての同一の型のコンポーネントを取得
componentList = (castedResult as Component).gameObject.GetComponents(type);
// 順番を取得 (アタッチされた順番が配列の順番となる)
componentIndex = Array.IndexOf(componentList, castedResult);
}

bool guiEnabled = GUI.enabled;

// 不正なアタッチ (見つからない場合) だったらフィールドは非アクティブ
if (componentIndex < 0)
{
componentIndex = 0;
GUI.enabled = false;
}

int indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;

var indexRect = new Rect(rect.xMax - EditorConst.ComponentIndexFieldWidth, rect.y, EditorConst.ComponentIndexFieldWidth, rect.height);

int editIndex = EditorGUI.IntField(indexRect, GUIContent.none, componentIndex);
if (editIndex != componentIndex)
{
// 設定された数字を切り替えたら同一オブジェクトのコンポーネントに差し替える
editIndex = Mathf.Clamp(editIndex, 0, componentList.Length - 1);
result = componentList[editIndex];
}

EditorGUI.indentLevel = indent;

GUI.enabled = guiEnabled;
}

if (result != property.objectReferenceValue)
{
property.objectReferenceValue = result;
Expand Down
47 changes: 45 additions & 2 deletions Packages/uGUI-Skinner/Editor/SkinnerEditorUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using System.Text.RegularExpressions;
using System.Text;
using System.Linq;
using UnityEngine.UI;
using System.Reflection;

namespace Pspkurara.UI.Skinner
{
Expand All @@ -15,6 +17,17 @@ public static class SkinnerEditorUtility

#region TempField

/// <summary>
/// 複数アタッチ不可能なコンポーネント類
/// </summary>
private static readonly List<Type> specificSingleComponents = new List<Type>(new Type[]
{
typeof(Transform),
typeof(CanvasGroup),
typeof(CanvasRenderer),
typeof(Canvas),
});

public static readonly Dictionary<Type, ComponentInfos> componentInfos = new Dictionary<Type, ComponentInfos>();

public sealed class ComponentInfos
Expand All @@ -28,13 +41,43 @@ public static ComponentInfos GetComponentInfos(Type type)
if (!componentInfos.ContainsKey(type))
{
ComponentInfos cInfo = new ComponentInfos();
cInfo.isComponent = type.IsSubclassOf(typeof(Component));
if (cInfo.isComponent) { cInfo.allowMultiplyComponent = !System.Attribute.IsDefined(type, typeof(DisallowMultipleComponent), true); }
cInfo.isComponent = type == typeof(Component) || type.IsSubclassOf(typeof(Component));
if (cInfo.isComponent)
{
// 複数不可能なコンポーネントはあらかじめ指定されている
if (specificSingleComponents.Exists(t => { return t == type || type.IsSubclassOf(t); }))
{
cInfo.allowMultiplyComponent = false;
}
else
{
cInfo.allowMultiplyComponent = IsDefinedDisallowMultiplyComponent(type);
}
}
componentInfos.Add(type, cInfo);
}
return componentInfos[type];
}

/// <summary>
/// 指定したコンポーネントタイプが<see cref="DisallowMultipleComponent"/>属性を持つか取得する
/// </summary>
/// <param name="type">調べたいコンポーネントの型</param>
/// <returns>
/// 自身か何らかの親クラスに属性を持つ場合は真
/// </returns>
private static bool IsDefinedDisallowMultiplyComponent(Type type)
{
if (type == null) return false;

if (type.IsDefined(typeof(DisallowMultipleComponent)))
{
return true;
}

return IsDefinedDisallowMultiplyComponent(type.BaseType);
}

#endregion

private static void FieldClean(SerializedProperty arrayObj, object defaultValue)
Expand Down

0 comments on commit 66b737c

Please sign in to comment.