/*WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW*\ ( ( ) )
|/ \| ) ) _((_
|| (c) Wanzyee Studio < wanzyeestudio.blogspot.com > || ( ( |_ _ |=n
|\ /| _____)) | ! ] U
\.ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ./ (_(__(S) |___*/
using UnityEditor;
using UnityEngine;
using System;
using System.Linq;
using Object = UnityEngine.Object;
namespace WanzyeeStudio.Editrix.Toolkit{
///
/// Group or ungroup scene UnityEngine.Transform for better arrangement.
///
///
///
/// Menu "GameObject/Group/Make Group" or hotkey Ctrl-G to group selected children.
/// Menu "GameObject/Group/Ungroup Parent" or hotkey Ctrl-Shift-G to ungroup selected parents.
/// Menu "GameObject/Group/Ungroup Children" or hotkey Ctrl-Alt-G to move selected children out from the group.
///
///
public static class ObjectGrouper{
#region Menu
///
/// Make a group UnityEngine.Transform contains selected children in the scene, with hotkey Ctrl-G.
///
[MenuItem("GameObject/Group/Make Group %g", false, 90)]
public static void MakeGroup(){
if(!MakeGroupValid()) throw new InvalidOperationException("No transform selected.");
Selection.objects = new Object[]{MakeGroup(null, Selection.transforms).gameObject};
}
///
/// Check if MakeGroup() valid, any scene UnityEngine.Transform selected.
///
/// true, if valid.
[MenuItem("GameObject/Group/Make Group %g", true)]
private static bool MakeGroupValid(){
return Selection.transforms.Any();
}
///
/// Ungroup children UnityEngine.Transform from selected parent in the scene, with hotkey Ctrl-Shift-G.
///
///
///
/// This'll destroy the parent if it has no other UnityEngine.Component.
/// Works like Transform.DetachChildren but detach to upward parent instead of root.
///
///
/*
* It causes crash when called with both destroying and selecting at once sometimes.
* It can be avoided by delay call, it may be an Unity internal execution order problem.
*/
[MenuItem("GameObject/Group/Ungroup Parent %#g", false, 90)]
public static void UngroupParent(){
if(!UngroupParentValid()) throw new InvalidOperationException("No parent transform selected.");
EditorApplication.delayCall += () => {
var _p = Selection.transforms.Where(_v => 0 < _v.childCount);
var _c = _p.SelectMany(_v => UngroupParent(_v, 2 > _v.GetComponents().Length));
Selection.objects = _c.Select(_v => _v.gameObject).ToArray();
};
}
///
/// Check if UngroupParent() valid, any scene parent UnityEngine.Transform selected.
///
/// true, if valid.
[MenuItem("GameObject/Group/Ungroup Parent %#g", true)]
private static bool UngroupParentValid(){
return Selection.transforms.Any(_v => 0 < _v.childCount);
}
///
/// Ungroup selected children UnityEngine.Transform to upward parent, with hotkey Ctrl-Alt-G.
///
[MenuItem("GameObject/Group/Ungroup Children %&g", false, 90)]
public static void UngroupChildren(){
if(!UngroupChildrenValid()) throw new InvalidOperationException("No child transform selected.");
var _c = Selection.transforms.Where(_v => null != _v.parent).OrderBy(_v => -_v.GetSiblingIndex());
foreach(var _v in _c) UngroupChild(_v);
}
///
/// Check if UngroupParent() valid, any scene child UnityEngine.Transform selected.
///
/// true, if valid.
[MenuItem("GameObject/Group/Ungroup Children %&g", true)]
private static bool UngroupChildrenValid(){
return Selection.transforms.Any(_v => null != _v.parent);
}
#endregion
#region Methods
///
/// Filter the top level transforms, excluding prefabs, ordered by sibling index.
///
/// The tops.
/// Transforms.
public static Transform[] FilterTops(params Transform[] transforms){
if(null == transforms) throw new ArgumentNullException("transforms");
var _t = transforms.Distinct().Where(_v => null != _v && !EditorUtility.IsPersistent(_v)).ToArray();
var _f = _t.Where(_v => !_t.Any(_o => _o != _v && _v.IsChildOf(_o)));
return _f.OrderBy(_v => EditrixUtility.GetObjectOrder(_v)).ToArray();
}
///
/// Make a group UnityEngine.Transform contains specified children.
///
/// The group parent.
/// Name.
/// Children.
public static Transform MakeGroup(string name, params Transform[] children){
if(null == children) throw new ArgumentNullException("children");
children = FilterTops(children);
if(!children.Any()) throw new ArgumentException("No children assigned.", "children");
var _g = new GameObject(string.IsNullOrEmpty(name) ? "New Group" : name);
var _result = children.All(_v => _v is RectTransform) ? _g.AddComponent() : _g.transform;
Undo.RegisterCreatedObjectUndo(_g, "Make Group");
Undo.SetTransformParent(_result, children[0].parent, "Arrange Group");
_result.SetSiblingIndex(children[0].GetSiblingIndex());
foreach(var _v in children) Undo.SetTransformParent(_v, _result, "Join Group");
return _result;
}
///
/// Ungroup all children UnityEngine.Transform from specified parent.
///
///
///
/// Optional to destroy the original parent after done.
/// Works like UnityEngine.Transform.DetachChildren but detach to upward parent instead of root.
///
///
/// The children from the parent.
/// Parent.
/// If set to true destroy.
///
public static Transform[] UngroupParent(Transform parent, bool destroy = false){
if(null == parent) throw new ArgumentNullException("parent");
var _result = parent.Cast().Reverse().ToArray();
if(!_result.Any()) throw new ArgumentException("No children included.", "parent");
foreach(var _v in _result) UngroupChild(_v);
if(destroy) Undo.DestroyObjectImmediate(parent.gameObject);
return _result;
}
///
/// Ungroup a child UnityEngine.Transform from current parent to upward.
///
/// The new parent.
/// Child.
public static Transform UngroupChild(Transform child){
if(null == child) throw new ArgumentNullException("child");
var _p = child.parent;
if(null == _p) throw new ArgumentException("Given child is a root.", "child");
Undo.SetTransformParent(child, _p.parent, "Ungroup Child");
child.SetAsLastSibling();
child.SetSiblingIndex(_p.GetSiblingIndex() + 1);
return child.parent;
}
#endregion
}
}