Skip to content

Instantly share code, notes, and snippets.

@dimmduh
Last active June 5, 2019 15:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dimmduh/bbff81ee6ae0eb4179c5c661d1c1363a to your computer and use it in GitHub Desktop.
Save dimmduh/bbff81ee6ae0eb4179c5c661d1c1363a to your computer and use it in GitHub Desktop.
Put somewhere in Editor folder
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
//version 0.2
[InitializeOnLoad]
public static class EditorHelperHotkeys
{
// private const double doublePressMaxDelay = 0.25;
//////////////////// SETTINGS ////////////
private static string newGroupNameFormat = "Group {0}";
private static int selectionUndoLimit = 20;
//////////////////// /SETTINGS ////////////
///
private static int nextGroupId = 1;
private static Object[] lastSelection;
private static MaxStack<Object[]> selectionUndo = new MaxStack<Object[]>(selectionUndoLimit);
private static bool justUndo;
private static bool justPush;
// private static double prevPressTime;
// private static KeyCode prevPressKeyCode = KeyCode.None;
static EditorHelperHotkeys()
{
if (SceneView.onSceneGUIDelegate != null)
{
SceneView.onSceneGUIDelegate -= OnSceneGUI;
}
SceneView.onSceneGUIDelegate += OnSceneGUI;
if (Selection.selectionChanged != null && Selection.selectionChanged.GetInvocationList().Contains(new Action(OnSelectionChanged)))
Selection.selectionChanged -= OnSelectionChanged;
Selection.selectionChanged += OnSelectionChanged;
}
private static void OnSelectionChanged()
{
//just canceled
if (justUndo)
{
justUndo = false;
return;
}
if (Selection.objects.Length == 0)
{
justPush = false;
return;
}
if (lastSelection == Selection.objects)
return;
selectionUndo.Push(Selection.objects);
lastSelection = Selection.objects;
justPush = true;
Debug.Log("Add = " + selectionUndo.Count);
}
[MenuItem("Edit/Undo Only Selection %#z")]
private static void UndoSelectionChanged()
{
if (selectionUndo.Count == 0)
return;
if (justPush)
{
selectionUndo.Pop();
justPush = false;
}
if (selectionUndo.Count > 0)
{
justUndo = true;
if (selectionUndo.Count > 1)
Selection.objects = selectionUndo.Pop();
else
Selection.objects = selectionUndo.Peek();
}
lastSelection = selectionUndo.Count == 0 ? null : selectionUndo.Peek();
Debug.Log("Undo = " + selectionUndo.Count);
}
private static void OnSceneGUI(SceneView sceneView)
{
OnUpdate();
}
private static void OnUpdate()
{
var e = Event.current;
if (e == null)
return;
if (!e.control || e.alt || e.type != EventType.KeyDown)
return;
// var diff = EditorApplication.timeSinceStartup - prevPressTime;
// prevPressTime = EditorApplication.timeSinceStartup;
// prevPressKeyCode = e.keyCode;
var applyGlobal = e.shift;
switch (e.type)
{
case EventType.KeyDown:
switch (e.keyCode)
{
case KeyCode.W:
ResetPosition(applyGlobal);
Event.current.Use();
break;
case KeyCode.E:
ResetRotation(applyGlobal);
Event.current.Use();
break;
case KeyCode.R:
ResetScale(applyGlobal);
// Event.current.Use();
break;
case KeyCode.T:
ResetTransform(applyGlobal);
Event.current.Use();
break;
}
break;
}
}
/*
private static void ResetKeys()
{
prevPressTime = 0;
prevPressKeyCode = KeyCode.None;
}
*/
[MenuItem("Edit/Group %g")]
private static void GroupObjects()
{
if (Selection.gameObjects.Length <= 1)
return;
var firstTransformInGroup = Selection.gameObjects[0].transform;
var sibling = firstTransformInGroup.GetSiblingIndex();
//detect is RectTransform or Transform
var useRectTransform = Selection.gameObjects.Any(go => go.transform is RectTransform);
//create new object
var name = string.Format(newGroupNameFormat, nextGroupId);
var groupTransform = new GameObject(name, useRectTransform ? typeof(RectTransform) : typeof(Transform)).transform;
nextGroupId++;
groupTransform.SetParent(firstTransformInGroup.parent);
groupTransform.SetSiblingIndex(sibling + 1);
Undo.RegisterCreatedObjectUndo(groupTransform.gameObject, "Group gameObjects");
foreach (var go in Selection.gameObjects)
{
Undo.SetTransformParent(go.transform, groupTransform, "Group gameObjects");
}
SetExpandedRecursive(groupTransform.gameObject, true);
Selection.activeObject = groupTransform.gameObject;
}
[MenuItem("Edit/UnParent %u")]
private static void UnParentObjects()
{
foreach (var go in Selection.gameObjects)
{
if (go.transform.parent != null)
Undo.SetTransformParent(go.transform, null, "UnParent gameObjects");
}
}
private static void ResetPosition(bool global)
{
foreach (var go in Selection.gameObjects)
{
Undo.RecordObject(go.transform, "Reset position");
if (global)
go.transform.position = Vector3.zero;
else
go.transform.localPosition = Vector3.zero;
}
}
private static void ResetRotation(bool global)
{
foreach (var go in Selection.gameObjects)
{
Undo.RecordObject(go.transform, "Reset rotation");
if (global)
go.transform.rotation = Quaternion.identity;
else
go.transform.localRotation = Quaternion.identity;
}
}
private static void ResetScale(bool global)
{
foreach (var go in Selection.gameObjects)
{
Undo.RecordObject(go.transform, "Reset scale");
go.transform.localScale = Vector3.one;
if (global)
{
var lossyScale = go.transform.lossyScale;
go.transform.localScale = new Vector3(1 / lossyScale.x, 1 / lossyScale.y, 1 / lossyScale.z);
}
}
}
private static void ResetTransform(bool global)
{
foreach (var go in Selection.gameObjects)
{
Undo.RecordObject(go.transform, "Reset transform");
go.transform.localScale = Vector3.one;
if (global)
{
go.transform.position = Vector3.zero;
go.transform.rotation = Quaternion.identity;
}
else
{
go.transform.localPosition = Vector3.zero;
go.transform.localRotation = Quaternion.identity;
var lossyScale = go.transform.lossyScale;
go.transform.localScale = new Vector3(1 / lossyScale.x, 1 / lossyScale.y, 1 / lossyScale.z);
}
}
}
///////////////// UTILS ////////////
public static void SetExpandedRecursive(GameObject go, bool expand)
{
var type = typeof(EditorWindow).Assembly.GetType("UnityEditor.SceneHierarchyWindow");
var methodInfo = type.GetMethod("SetExpandedRecursive");
try
{
EditorApplication.ExecuteMenuItem("Window/General/Hierarchy");
var window = EditorWindow.focusedWindow;
methodInfo.Invoke(window, new object[] {go.GetInstanceID(), expand});
}
catch (Exception)
{
// ignored
}
}
}
/// <summary>
/// Generic stack implementation with a maximum limit
/// When something is pushed on the last item is removed from the list
/// @see http://ntsblog.homedev.com.au/index.php/2010/05/06/c-stack-with-maximum-limit/
/// </summary>
[Serializable]
public class MaxStack<T>
{
#region Fields
private int _limit;
private LinkedList<T> _list;
#endregion
#region Constructors
public MaxStack(int maxSize)
{
_limit = maxSize;
_list = new LinkedList<T>();
}
#endregion
#region Public Stack Implementation
public void Push(T value)
{
if (_list.Count == _limit)
{
_list.RemoveLast();
}
_list.AddFirst(value);
}
public T Pop()
{
if (_list.Count > 0)
{
T value = _list.First.Value;
_list.RemoveFirst();
return value;
}
else
{
throw new InvalidOperationException("The Stack is empty");
}
}
public T Peek()
{
if (_list.Count > 0)
{
T value = _list.First.Value;
return value;
}
else
{
throw new InvalidOperationException("The Stack is empty");
}
}
public void Clear()
{
_list.Clear();
}
public int Count
{
get { return _list.Count; }
}
/// <summary>
/// Checks if the top object on the stack matches the value passed in
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public bool IsTop(T value)
{
bool result = false;
if (this.Count > 0)
{
result = Peek().Equals(value);
}
return result;
}
public bool Contains(T value)
{
bool result = false;
if (this.Count > 0)
{
result = _list.Contains(value);
}
return result;
}
public IEnumerator GetEnumerator()
{
return _list.GetEnumerator();
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment