Initial commit

This commit is contained in:
AbstractConcept 2022-09-13 00:36:34 -05:00
commit 3c7cc0c973
8391 changed files with 704313 additions and 0 deletions

View file

@ -0,0 +1,2 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Unity.2D.SpriteShape.Editor")]

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b8de732c98460ec4ca63677f37beb1e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Path
{
public class GenericScriptablePath<T> : ScriptablePath
{
[SerializeField]
private List<T> m_Data = new List<T>();
public T[] data
{
get { return m_Data.ToArray(); }
set
{
if (value.Length != pointCount)
throw new Exception("Custom data count does not match control point count");
m_Data.Clear();
m_Data.AddRange(value);
}
}
public override void Clear()
{
base.Clear();
m_Data.Clear();
}
public override void AddPoint(ControlPoint controlPoint)
{
base.AddPoint(controlPoint);
m_Data.Add(Create());
}
public override void InsertPoint(int index, ControlPoint controlPoint)
{
base.InsertPoint(index, controlPoint);
m_Data.Insert(index, Create());
}
public override void RemovePoint(int index)
{
base.RemovePoint(index);
Destroy(m_Data[index]);
m_Data.RemoveAt(index);
}
public T GetData(int index)
{
return m_Data[index];
}
public void SetData(int index, T data)
{
m_Data[index] = data;
}
protected virtual T Create()
{
return Activator.CreateInstance<T>();
}
protected virtual void Destroy(T data) { }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 91ab30a448166b74e99d488f537bfc67
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,120 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.EditorTools;
namespace UnityEditor.U2D.Path
{
public class GenericScriptablePathInspector<U,T> : ScriptablePathInspector where U : ScriptableData<T>
{
private List<U> m_DataObjects = new List<U>();
private List<U> m_SelectedDataObjects = new List<U>();
private Editor m_CachedEditor = null;
private void OnEnable()
{
PrepareDataObjects();
}
private void OnDestroy()
{
DestroyDataObjects();
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
DoCustomDataInspector();
}
protected void DoCustomDataInspector()
{
PrepareDataObjects();
if (m_SelectedDataObjects.Count > 0)
{
CreateCachedEditor(m_SelectedDataObjects.ToArray(), null, ref m_CachedEditor);
EditorGUI.BeginChangeCheck();
m_CachedEditor.OnInspectorGUI();
if (EditorGUI.EndChangeCheck())
SetDataObjects();
}
}
private void PrepareDataObjects()
{
var elementCount = 0;
m_SelectedDataObjects.Clear();
foreach(var path in paths)
elementCount += path.pointCount;
while (m_DataObjects.Count < elementCount)
CreateDataObject();
var index = 0;
foreach(var path in paths)
{
var genericPath = path as GenericScriptablePath<T>;
var customDataArray = genericPath.data;
var length = customDataArray.Length;
for (var i = 0; i < length; ++i)
{
var dataObject = m_DataObjects[index + i];
dataObject.data = customDataArray[i];
if (path.selection.Contains(i))
{
dataObject.owner = path.owner;
dataObject.index = i;
m_SelectedDataObjects.Add(dataObject);
}
}
index += length;
}
}
private void SetDataObjects()
{
var index = 0;
foreach(var path in paths)
{
var genericPath = path as GenericScriptablePath<T>;
var customDataArray = genericPath.data;
var length = customDataArray.Length;
for (var i = 0; i < length; ++i)
customDataArray[i] = m_DataObjects[index + i].data;
genericPath.data = customDataArray;
index += length;
}
}
private U CreateDataObject()
{
var dataObject = ScriptableObject.CreateInstance<U>();
m_DataObjects.Add(dataObject);
return dataObject;
}
private void DestroyDataObjects()
{
foreach (var customDataObject in m_DataObjects)
DestroyImmediate(customDataObject);
m_DataObjects.Clear();
m_SelectedDataObjects.Clear();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8d7f8780c69f9742b827ffd638225fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,123 @@
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.EditorTools;
namespace UnityEditor.U2D.Path
{
public abstract class PathComponentEditor<T> : Editor where T : ScriptablePath
{
private static class Contents
{
public static readonly GUIContent snappingLabel = new GUIContent("Snapping", "Snap points using the snap settings");
}
private Editor m_CachedEditor = null;
// Returns true on Changed.
internal bool DoEditButtonChecked<U>(GUIContent icon, string label) where U : PathEditorTool<T>
{
const float kButtonWidth = 33;
const float kButtonHeight = 23;
const float k_SpaceBetweenLabelAndButton = 5;
var buttonStyle = new GUIStyle("EditModeSingleButton");
var rect = EditorGUILayout.GetControlRect(true, kButtonHeight, buttonStyle);
var buttonRect = new Rect(rect.xMin + EditorGUIUtility.labelWidth, rect.yMin, kButtonWidth, kButtonHeight);
var labelContent = new GUIContent(label);
var labelSize = GUI.skin.label.CalcSize(labelContent);
var labelRect = new Rect(
buttonRect.xMax + k_SpaceBetweenLabelAndButton,
rect.yMin + (rect.height - labelSize.y) * .5f,
labelSize.x,
rect.height);
bool hasChanged = false;
using (new EditorGUI.DisabledGroupScope(!EditorToolManager.IsAvailable<U>()))
{
using (var check = new EditorGUI.ChangeCheckScope())
{
var isActive = GUI.Toggle(buttonRect, EditorToolManager.IsActiveTool<U>(), icon, buttonStyle);
GUI.Label(labelRect, label);
if (check.changed)
{
if (isActive)
EditorTools.EditorTools.SetActiveTool<U>();
else
EditorTools.EditorTools.RestorePreviousTool();
hasChanged = true;
}
}
}
return hasChanged;
}
protected void DoEditButton<U>(GUIContent icon, string label) where U : PathEditorTool<T>
{
DoEditButtonChecked<U>(icon, label);
}
protected void DoPathInspector<U>() where U : PathEditorTool<T>
{
if (EditorToolManager.IsActiveTool<U>() && EditorToolManager.IsAvailable<U>())
{
var paths = EditorToolManager.GetEditorTool<U>().paths;
CreateCachedEditor(paths, null, ref m_CachedEditor);
if (m_CachedEditor == null) //Needed to avoid a nullref on exiting playmode
return;
using (var check = new EditorGUI.ChangeCheckScope())
{
m_CachedEditor.OnInspectorGUI();
if (check.changed)
EditorToolManager.GetEditorTool<U>().SetShapes();
}
}
}
protected void DoSnappingInspector<U>() where U : PathEditorTool<T>
{
if (EditorToolManager.IsActiveTool<U>() && EditorToolManager.IsAvailable<U>())
{
var tool = EditorToolManager.GetEditorTool<U>();
tool.enableSnapping = EditorGUILayout.Toggle(Contents.snappingLabel, tool.enableSnapping);
}
}
protected void DoOpenEndedInspector<U>(SerializedProperty isOpenEndedProperty) where U : PathEditorTool<T>
{
serializedObject.Update();
using (var check = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.PropertyField(isOpenEndedProperty);
if (check.changed)
{
if (EditorToolManager.IsActiveTool<U>() && EditorToolManager.IsAvailable<U>())
{
var paths = EditorToolManager.GetEditorTool<U>().paths;
foreach (var path in paths)
{
path.undoObject.RegisterUndo("Set Open Ended");
path.isOpenEnded = isOpenEndedProperty.boolValue;
}
}
}
}
serializedObject.ApplyModifiedProperties();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 79c3c0b6ebc836f438b76a34f04dd076
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,494 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditor.U2D.Path.GUIFramework;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.U2D.Path
{
public static class PathEditorToolContents
{
internal static readonly GUIContent shapeToolIcon = IconContent("ShapeTool", "Start editing the Shape in the Scene View.");
internal static readonly GUIContent shapeToolPro = IconContent("ShapeToolPro", "Start editing the Shape in the Scene View.");
internal static GUIContent IconContent(string name, string tooltip = null)
{
return new GUIContent(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/" + name + ".png"), tooltip);
}
public static GUIContent icon
{
get
{
if (EditorGUIUtility.isProSkin)
return shapeToolPro;
return shapeToolIcon;
}
}
}
internal interface IDuringSceneGuiTool
{
void DuringSceneGui(SceneView sceneView);
bool IsAvailable();
}
[InitializeOnLoad]
internal class EditorToolManager
{
private static List<IDuringSceneGuiTool> m_Tools = new List<IDuringSceneGuiTool>();
static EditorToolManager()
{
SceneView.duringSceneGui += DuringSceneGui;
}
internal static void Add(IDuringSceneGuiTool tool)
{
if (!m_Tools.Contains(tool) && tool is EditorTool)
m_Tools.Add(tool);
}
internal static void Remove(IDuringSceneGuiTool tool)
{
if (m_Tools.Contains(tool))
m_Tools.Remove(tool);
}
internal static bool IsActiveTool<T>() where T : EditorTool
{
return EditorTools.EditorTools.activeToolType.Equals(typeof(T));
}
internal static bool IsAvailable<T>() where T : EditorTool
{
var tool = GetEditorTool<T>();
if (tool != null)
return tool.IsAvailable();
return false;
}
internal static T GetEditorTool<T>() where T : EditorTool
{
foreach(var tool in m_Tools)
{
if (tool.GetType().Equals(typeof(T)))
return tool as T;
}
return null;
}
private static void DuringSceneGui(SceneView sceneView)
{
foreach (var tool in m_Tools)
{
if (tool.IsAvailable() && EditorTools.EditorTools.IsActiveTool(tool as EditorTool))
tool.DuringSceneGui(sceneView);
}
}
}
public abstract class PathEditorTool<T> : EditorTool, IDuringSceneGuiTool where T : ScriptablePath
{
private Dictionary<UnityObject, T> m_Paths = new Dictionary<UnityObject, T>();
private IGUIState m_GUIState = new GUIState();
private Dictionary<UnityObject, PathEditor> m_PathEditors = new Dictionary<UnityObject, PathEditor>();
private Dictionary<UnityObject, SerializedObject> m_SerializedObjects = new Dictionary<UnityObject, SerializedObject>();
private MultipleEditablePathController m_Controller = new MultipleEditablePathController();
private PointRectSelector m_RectSelector = new PointRectSelector();
private bool m_IsActive = false;
internal T[] paths
{
get { return m_Paths.Values.ToArray(); }
}
public bool enableSnapping
{
get { return m_Controller.enableSnapping; }
set { m_Controller.enableSnapping = value; }
}
public override GUIContent toolbarIcon
{
get { return PathEditorToolContents.icon; }
}
public override bool IsAvailable()
{
return targets.Count() > 0;
}
public T GetPath(UnityObject targetObject)
{
var path = default(T);
m_Paths.TryGetValue(targetObject, out path);
return path;
}
public void SetPath(UnityObject target)
{
var path = GetPath(target);
path.localToWorldMatrix = Matrix4x4.identity;
var undoName = Undo.GetCurrentGroupName();
var serializedObject = GetSerializedObject(target);
serializedObject.UpdateIfRequiredOrScript();
SetShape(path, serializedObject);
Undo.SetCurrentGroupName(undoName);
}
private void RepaintInspectors()
{
var editorWindows = Resources.FindObjectsOfTypeAll<EditorWindow>();
foreach (var editorWindow in editorWindows)
{
if (editorWindow.titleContent.text == "Inspector")
editorWindow.Repaint();
}
}
private void OnEnable()
{
m_IsActive = false;
EditorToolManager.Add(this);
SetupRectSelector();
HandleActivation();
EditorTools.EditorTools.activeToolChanged += HandleActivation;
}
private void OnDestroy()
{
EditorToolManager.Remove(this);
EditorTools.EditorTools.activeToolChanged -= HandleActivation;
UnregisterCallbacks();
}
private void HandleActivation()
{
if (m_IsActive == false && EditorTools.EditorTools.IsActiveTool(this))
Activate();
else if (m_IsActive)
Deactivate();
}
private void Activate()
{
m_IsActive = true;
RegisterCallbacks();
InitializeCache();
OnActivate();
}
private void Deactivate()
{
OnDeactivate();
DestroyCache();
UnregisterCallbacks();
m_IsActive = false;
}
private void RegisterCallbacks()
{
UnregisterCallbacks();
Selection.selectionChanged += SelectionChanged;
EditorApplication.playModeStateChanged += PlayModeStateChanged;
Undo.undoRedoPerformed += UndoRedoPerformed;
}
private void UnregisterCallbacks()
{
Selection.selectionChanged -= SelectionChanged;
EditorApplication.playModeStateChanged -= PlayModeStateChanged;
Undo.undoRedoPerformed -= UndoRedoPerformed;
}
private void DestroyCache()
{
foreach (var pair in m_Paths)
{
var path = pair.Value;
if (path != null)
{
Undo.ClearUndo(path);
UnityObject.DestroyImmediate(path);
}
}
m_Paths.Clear();
m_Controller.ClearPaths();
m_PathEditors.Clear();
m_SerializedObjects.Clear();
}
private void UndoRedoPerformed()
{
ForEachTarget((target) =>
{
var path = GetPath(target);
if (!path.modified)
InitializePath(target);
});
}
private void SelectionChanged()
{
InitializeCache();
}
private void PlayModeStateChanged(PlayModeStateChange stateChange)
{
if (stateChange == PlayModeStateChange.EnteredEditMode)
EditorApplication.delayCall += () => { InitializeCache(); }; //HACK: At this point target is null. Let's wait to next frame to refresh.
}
private void SetupRectSelector()
{
m_RectSelector.onSelectionBegin = BeginSelection;
m_RectSelector.onSelectionChanged = UpdateSelection;
m_RectSelector.onSelectionEnd = EndSelection;
}
private void ForEachTarget(Action<UnityObject> action)
{
foreach(var target in targets)
{
if (target == null)
continue;
action(target);
}
}
private void InitializeCache()
{
m_Controller.ClearPaths();
ForEachTarget((target) =>
{
var path = GetOrCreatePath(target);
var pointCount = path.pointCount;
InitializePath(target);
if (pointCount != path.pointCount)
path.selection.Clear();
CreatePathEditor(target);
m_Controller.AddPath(path);
});
}
private void InitializePath(UnityObject target)
{
IShape shape = null;
ControlPoint[] controlPoints = null;
try
{
shape = GetShape(target);
controlPoints = shape.ToControlPoints();
}
catch (Exception e)
{
Debug.LogError(e.Message);
}
var path = GetPath(target);
path.Clear();
if (shape != null && controlPoints != null)
{
path.localToWorldMatrix = Matrix4x4.identity;
path.shapeType = shape.type;
path.isOpenEnded = shape.isOpenEnded;
foreach (var controlPoint in controlPoints)
path.AddPoint(controlPoint);
}
Initialize(path, GetSerializedObject(target));
}
private T GetOrCreatePath(UnityObject targetObject)
{
var path = GetPath(targetObject);
if (path == null)
{
path = ScriptableObject.CreateInstance<T>();
path.owner = targetObject;
m_Paths[targetObject] = path;
}
return path;
}
private PathEditor GetPathEditor(UnityObject target)
{
PathEditor pathEditor;
m_PathEditors.TryGetValue(target, out pathEditor);
return pathEditor;
}
private void CreatePathEditor(UnityObject target)
{
var pathEditor = new PathEditor();
pathEditor.controller = m_Controller;
pathEditor.drawerOverride = GetCustomDrawer(target);
m_PathEditors[target] = pathEditor;
}
private SerializedObject GetSerializedObject(UnityObject target)
{
var serializedObject = default(SerializedObject);
if (!m_SerializedObjects.TryGetValue(target, out serializedObject))
{
serializedObject = new SerializedObject(target);
m_SerializedObjects[target] = serializedObject;
}
return serializedObject;
}
void IDuringSceneGuiTool.DuringSceneGui(SceneView sceneView)
{
if (m_GUIState.eventType == EventType.Layout)
m_Controller.ClearClosestPath();
m_RectSelector.OnGUI();
bool changed = false;
ForEachTarget((target) =>
{
var path = GetPath(target);
if (path != null)
{
path.localToWorldMatrix = GetLocalToWorldMatrix(target);
path.forward = GetForward(target);
path.up = GetUp(target);
path.right = GetRight(target);
m_Controller.editablePath = path;
using (var check = new EditorGUI.ChangeCheckScope())
{
var pathEditor = GetPathEditor(target);
pathEditor.linearTangentIsZero = GetLinearTangentIsZero(target);
pathEditor.OnGUI();
OnCustomGUI(path);
changed |= check.changed;
}
}
});
if (changed)
{
SetShapes();
RepaintInspectors();
}
}
private void BeginSelection(ISelector<Vector3> selector, bool isAdditive)
{
m_Controller.RegisterUndo("Selection");
if (isAdditive)
{
ForEachTarget((target) =>
{
var path = GetPath(target);
path.selection.BeginSelection();
});
}
else
{
UpdateSelection(selector);
}
}
private void UpdateSelection(ISelector<Vector3> selector)
{
var repaintInspectors = false;
ForEachTarget((target) =>
{
var path = GetPath(target);
repaintInspectors |= path.Select(selector);
});
if (repaintInspectors)
RepaintInspectors();
}
private void EndSelection(ISelector<Vector3> selector)
{
ForEachTarget((target) =>
{
var path = GetPath(target);
path.selection.EndSelection(true);
});
}
internal void SetShapes()
{
ForEachTarget((target) =>
{
SetPath(target);
});
}
private Transform GetTransform(UnityObject target)
{
return (target as Component).transform;
}
private Matrix4x4 GetLocalToWorldMatrix(UnityObject target)
{
return GetTransform(target).localToWorldMatrix;
}
private Vector3 GetForward(UnityObject target)
{
return GetTransform(target).forward;
}
private Vector3 GetUp(UnityObject target)
{
return GetTransform(target).up;
}
private Vector3 GetRight(UnityObject target)
{
return GetTransform(target).right;
}
protected abstract IShape GetShape(UnityObject target);
protected virtual void Initialize(T path, SerializedObject serializedObject) { }
protected abstract void SetShape(T path, SerializedObject serializedObject);
protected virtual void OnActivate() { }
protected virtual void OnDeactivate() { }
protected virtual void OnCustomGUI(T path) { }
protected virtual bool GetLinearTangentIsZero(UnityObject target) { return false; }
protected virtual IDrawer GetCustomDrawer(UnityObject target) { return null; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 320732be5a65ff84ea451c5bf9700876
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,108 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditor.U2D.Path.GUIFramework;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.U2D.Path
{
public static class PathEditorToolExtensions
{
public static void CycleTangentMode<T>(this PathEditorTool<T> pathEditorTool) where T : ScriptablePath
{
var first = true;
var mixed = false;
var tangentMode = TangentMode.Linear;
var targets = pathEditorTool.targets;
foreach(var target in targets)
{
var path = pathEditorTool.GetPath(target);
if (path.selection.Count == 0)
continue;
for (var i = 0; i < path.pointCount; ++i)
{
if (!path.selection.Contains(i))
continue;
var point = path.GetPoint(i);
if (first)
{
first = false;
tangentMode = point.tangentMode;
}
else if (point.tangentMode != tangentMode)
{
mixed = true;
break;
}
}
if (mixed)
break;
}
if (mixed)
tangentMode = TangentMode.Linear;
else
tangentMode = GetNextTangentMode(tangentMode);
foreach(var target in targets)
{
var path = pathEditorTool.GetPath(target);
if (path.selection.Count == 0)
continue;
path.undoObject.RegisterUndo("Cycle Tangent Mode");
for (var i = 0; i < path.pointCount; ++i)
{
if (!path.selection.Contains(i))
continue;
path.SetTangentMode(i, tangentMode);
}
pathEditorTool.SetPath(target);
}
}
public static void MirrorTangent<T>(this PathEditorTool<T> pathEditorTool) where T : ScriptablePath
{
var targets = pathEditorTool.targets;
foreach(var target in targets)
{
var path = pathEditorTool.GetPath(target);
if (path.selection.Count == 0)
continue;
path.undoObject.RegisterUndo("Mirror Tangents");
for (var i = 0; i < path.pointCount; ++i)
{
if (!path.selection.Contains(i))
continue;
path.MirrorTangent(i);
}
pathEditorTool.SetPath(target);
}
}
private static TangentMode GetNextTangentMode(TangentMode tangentMode)
{
return (TangentMode)((((int)tangentMode) + 1) % Enum.GetValues(typeof(TangentMode)).Length);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 94a1e3e609709aa4f9106a9aeea179f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.U2D.Path
{
public class ScriptableData<T> : ScriptableObject
{
[SerializeField]
private T m_Data;
public UnityObject owner { get; set; }
public int index { get; set; }
public T data
{
get { return m_Data; }
set { m_Data = value; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ae511f1b2818bc54f87b84a327b16f71
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,118 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.U2D.Path
{
public class ScriptablePath : ScriptableObject, IEditablePath, IUndoObject
{
[SerializeField]
private EditablePath m_EditablePath = new EditablePath();
[SerializeField]
private bool m_Modified = false;
internal bool modified
{
get { return m_Modified; }
}
internal UnityObject owner { get; set; }
public ShapeType shapeType
{
get { return m_EditablePath.shapeType; }
set { m_EditablePath.shapeType = value; }
}
public IUndoObject undoObject
{
get { return this; }
set { }
}
public ISelection<int> selection
{
get { return m_EditablePath.selection; }
}
public Matrix4x4 localToWorldMatrix
{
get { return m_EditablePath.localToWorldMatrix; }
set { m_EditablePath.localToWorldMatrix = value; }
}
public Vector3 forward
{
get { return m_EditablePath.forward; }
set { m_EditablePath.forward = value; }
}
public Vector3 up
{
get { return m_EditablePath.up; }
set { m_EditablePath.up = value; }
}
public Vector3 right
{
get { return m_EditablePath.right; }
set { m_EditablePath.right = value; }
}
public bool isOpenEnded
{
get { return m_EditablePath.isOpenEnded; }
set { m_EditablePath.isOpenEnded = value; }
}
public int pointCount
{
get { return m_EditablePath.pointCount; }
}
public bool Select(ISelector<Vector3> selector)
{
return m_EditablePath.Select(selector);
}
public virtual void Clear()
{
m_EditablePath.Clear();
}
public virtual ControlPoint GetPoint(int index)
{
return m_EditablePath.GetPoint(index);
}
public virtual void SetPoint(int index, ControlPoint controlPoint)
{
m_EditablePath.SetPoint(index, controlPoint);
}
public virtual void AddPoint(ControlPoint controlPoint)
{
m_EditablePath.AddPoint(controlPoint);
}
public virtual void InsertPoint(int index, ControlPoint controlPoint)
{
m_EditablePath.InsertPoint(index, controlPoint);
}
public virtual void RemovePoint(int index)
{
m_EditablePath.RemovePoint(index);
}
void IUndoObject.RegisterUndo(string name)
{
Undo.RegisterCompleteObjectUndo(this, name);
m_Modified = true;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c208d96210d896247a45095d5fa9bf09
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,233 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace UnityEditor.U2D.Path
{
[CanEditMultipleObjects]
[CustomEditor(typeof(ScriptablePath), true)]
public class ScriptablePathInspector : Editor
{
private static class Contents
{
public static readonly GUIContent linearIcon = IconContent("TangentLinear", "TangentLinearPro", "Linear");
public static readonly GUIContent continuousIcon = IconContent("TangentContinuous", "TangentContinuousPro", "Continuous");
public static readonly GUIContent brokenIcon = IconContent("TangentBroken", "TangentBrokenPro", "Broken");
public static readonly GUIContent positionLabel = new GUIContent("Position", "Position of the Control Point");
public static readonly GUIContent enableSnapLabel = new GUIContent("Snapping", "Snap points using the snap settings");
public static readonly GUIContent tangentModeLabel = new GUIContent("Tangent Mode");
public static readonly GUIContent pointLabel = new GUIContent("Point");
private static GUIContent IconContent(string name, string tooltip = null)
{
return new GUIContent(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/" + name + ".png"), tooltip);
}
private static GUIContent IconContent(string personal, string pro, string tooltip)
{
if (EditorGUIUtility.isProSkin)
return IconContent(pro, tooltip);
return IconContent(personal, tooltip);
}
}
private List<ScriptablePath> m_Paths = null;
private bool m_Dragged = false;
protected List<ScriptablePath> paths
{
get
{
if (m_Paths == null)
m_Paths = targets.Select( t => t as ScriptablePath).ToList();
return m_Paths;
}
}
public override void OnInspectorGUI()
{
DoTangentModeInspector();
DoPositionInspector();
}
protected void DoTangentModeInspector()
{
if (!IsAnyShapeType(ShapeType.Spline))
return;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel(Contents.tangentModeLabel);
using (new EditorGUI.DisabledGroupScope(!IsAnyPointSelected()))
{
if (DoToggle(GetToggleStateFromTangentMode(TangentMode.Linear), Contents.linearIcon))
SetMixedTangentMode(TangentMode.Linear);
if (DoToggle(GetToggleStateFromTangentMode(TangentMode.Continuous), Contents.continuousIcon))
SetMixedTangentMode(TangentMode.Continuous);
if (DoToggle(GetToggleStateFromTangentMode(TangentMode.Broken), Contents.brokenIcon))
SetMixedTangentMode(TangentMode.Broken);
}
EditorGUILayout.EndHorizontal();
}
protected void DoPositionInspector()
{
var showMixedValue = EditorGUI.showMixedValue;
var wideMode = EditorGUIUtility.wideMode;
var position = Vector3.zero;
var isMixed = GetMixedPosition(out position);
EditorGUI.showMixedValue = isMixed;
EditorGUIUtility.wideMode = true;
using (new EditorGUI.DisabledGroupScope(!IsAnyPointSelected()))
{
if (GUIUtility.hotControl == 0)
m_Dragged = false;
EditorGUI.BeginChangeCheck();
var delta = EditorGUILayout.Vector2Field(Contents.positionLabel, position) - (Vector2)position;
if (EditorGUI.EndChangeCheck())
{
if (m_Dragged == false)
{
foreach(var path in paths)
path.undoObject.RegisterUndo("Point Position");
m_Dragged = true;
}
SetMixedDeltaPosition(delta);
}
}
EditorGUI.showMixedValue = showMixedValue;
EditorGUIUtility.wideMode = wideMode;
}
private bool DoToggle(bool value, GUIContent icon)
{
const float kButtonWidth = 33f;
const float kButtonHeight = 23f;
var buttonStyle = new GUIStyle("EditModeSingleButton");
var changed = false;
using (var check = new EditorGUI.ChangeCheckScope())
{
value = GUILayout.Toggle(value, icon, buttonStyle, GUILayout.Width(kButtonWidth), GUILayout.Height(kButtonHeight));
changed = check.changed;
}
return value && changed;
}
private bool GetToggleStateFromTangentMode(TangentMode mode)
{
foreach(var path in paths)
{
var selection = path.selection;
foreach (var index in selection.elements)
if (path.GetPoint(index).tangentMode != mode)
return false;
}
return true;
}
private void SetMixedTangentMode(TangentMode tangentMode)
{
foreach(var path in paths)
{
path.undoObject.RegisterUndo("Tangent Mode");
foreach (var index in path.selection.elements)
path.SetTangentMode(index, tangentMode);
}
SceneView.RepaintAll();
}
private bool GetMixedPosition(out Vector3 position)
{
var first = true;
position = Vector3.zero;
foreach(var path in paths)
{
var selection = path.selection;
var matrix = path.localToWorldMatrix;
path.localToWorldMatrix = Matrix4x4.identity;
foreach (var index in selection.elements)
{
var controlPoint = path.GetPoint(index);
if (first)
{
position = controlPoint.position;
first = false;
}
else if (position != controlPoint.position)
{
return true;
}
}
path.localToWorldMatrix = matrix;
}
return false;
}
private void SetMixedDeltaPosition(Vector3 delta)
{
foreach(var path in paths)
{
var selection = path.selection;
var matrix = path.localToWorldMatrix;
path.localToWorldMatrix = Matrix4x4.identity;
foreach (var index in selection.elements)
{
var controlPoint = path.GetPoint(index);
controlPoint.position += delta;
path.SetPoint(index, controlPoint);
}
path.localToWorldMatrix = matrix;
}
}
private bool IsAnyShapeType(ShapeType shapeType)
{
foreach(var path in paths)
if (path.shapeType == shapeType)
return true;
return false;
}
protected bool IsAnyPointSelected()
{
foreach(var path in paths)
if (path.selection.Count > 0)
return true;
return false;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c5abda88d831f347a177bb63ff287b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: