Skip to content

khRiku/YangEngine

Repository files navigation

fileFormatVersion: 2 guid: 949e01a86a7a65d4facebf6e5c01e0b9 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant:

using System; using System.Collections.Generic; using System.Linq; using UnityEditor.IMGUI.Controls; using UnityEngine; using UnityEngine.SceneManagement; using UnityObject = UnityEngine.Object;

namespace UnityEditor.TreeViewExamples {

class TransformTreeView : TreeView
{
	public TransformTreeView (TreeViewState state)
		: base (state)
	{
		Reload ();
	}

    /// <summary>
    /// 创建 根节点, 分两种方式, 一下代码采用的第 2 种, 需要重写 BuildRows 函数
    /// 1:创建根节点和所有的TreeViewItem
    /// 2: 只创建根节点,这种需要重写一些函数, 好处是比较适合那些有很多TreeViewItem 显示的情况
    /// </summary>
    /// <returns></returns>
	protected override TreeViewItem BuildRoot()
	{
		return new TreeViewItem {id = 0, depth = -1};
	}

    /// <summary>
    /// 在Reload 函数之后调用,
    /// 创建需要显示的 TreeViewItem
    /// </summary>
	protected override IList<TreeViewItem> BuildRows(TreeViewItem root)
	{
		var rows = GetRows () ?? new List<TreeViewItem> (200);

		Scene scene = SceneManager.GetSceneAt (0);

		// We use the GameObject instanceIDs as ids for items as we want to 
		// select the game objects and not the transform components.
		rows.Clear ();
		var gameObjectRoots = scene.GetRootGameObjects ();
		foreach (var gameObject in gameObjectRoots)
		{
			var item = CreateTreeViewItemForGameObject (gameObject);
			root.AddChild (item);
			rows.Add (item);
			if (gameObject.transform.childCount > 0)
			{
				if (IsExpanded (item.id))
				{
					AddChildrenRecursive (gameObject, item, rows);
				}
				else
				{
                    //没展开, 就创建个占位的
					item.children = CreateChildListForCollapsedParent ();
				}
			}
		}

        //根据子、父节点来设置该TreeViewItem和子物体的 depth 值
		SetupDepthsFromParentsAndChildren (root);
		return rows;
	}

	void AddChildrenRecursive (GameObject go, TreeViewItem item, IList<TreeViewItem> rows)
	{
		int childCount = go.transform.childCount;

		item.children = new List<TreeViewItem> (childCount);
		for (int i = 0; i < childCount; ++i)
		{
			var childTransform = go.transform.GetChild (i);
			var childItem = CreateTreeViewItemForGameObject (childTransform.gameObject);
			item.AddChild (childItem);
			rows.Add (childItem);

            //子节点处理
			if (childTransform.childCount > 0)
			{
				if (IsExpanded (childItem.id))
				{
					AddChildrenRecursive (childTransform.gameObject, childItem, rows);
				}
				else
				{
					childItem.children = CreateChildListForCollapsedParent ();
				}
			}
		}
	}

	static TreeViewItem CreateTreeViewItemForGameObject (GameObject gameObject)
	{
		// We can use the GameObject instanceID for TreeViewItem id, as it ensured to be unique among other items in the tree.
		// To optimize reload time we could delay fetching the transform.name until it used for rendering (prevents allocating strings 
		// for items not rendered in large trees)
		// We just set depth to -1 here and then call SetupDepthsFromParentsAndChildren at the end of BuildRootAndRows to set the depths.
		return new TreeViewItem(gameObject.GetInstanceID(), -1, gameObject.name);
	}

    /// <summary>
    /// 没有在BuildRoot 函数中创建所有的 TreeViewItem, 就需要重写这个函数
    /// 用于显示被折叠的 TreeViewItem
    /// </summary>
    protected override IList<int> GetAncestors (int id)
	{
		// The backend needs to provide us with this info since the item with id
		// may not be present in the rows
		var transform = GetGameObject(id).transform;

		List<int> ancestors = new List<int> ();
		while (transform.parent != null)
		{
			ancestors.Add (transform.parent.gameObject.GetInstanceID ());
			transform = transform.parent;
		}

		return ancestors;
	}

    /// <summary>
    /// 没有在BuildRoot 函数中创建所有的 TreeViewItem, 就需要重写这个函数
    ///  用于展开整个 子树
    /// </summary>

	protected override IList<int> GetDescendantsThatHaveChildren (int id)
	{
		Stack<Transform> stack = new Stack<Transform> ();

		var start = GetGameObject(id).transform;
		stack.Push (start);

		var parents = new List<int> ();
		while (stack.Count > 0)
		{
			Transform current = stack.Pop ();
			parents.Add (current.gameObject.GetInstanceID ());
			for (int i = 0; i < current.childCount; ++i)
			{
				if (current.childCount > 0)
					stack.Push (current.GetChild (i));
			}
		}

		return parents;
	}

	GameObject GetGameObject (int instanceID)
	{
		return (GameObject)EditorUtility.InstanceIDToObject(instanceID);
	}

    /// <summary>
    /// Custom GUI
    /// 自定义UI, 在这个函数调用前那个"三角形”已经绘制了
    /// </summary>
    /// <param name="args"></param>

    protected override void RowGUI (RowGUIArgs args)
	{
		Event evt = Event.current;
		extraSpaceBeforeIconAndLabel = 18f;

		// GameObject isStatic toggle 
		var gameObject = GetGameObject(args.item.id);
		if (gameObject == null)
			return;

		Rect toggleRect = args.rowRect;
		toggleRect.x += GetContentIndent(args.item);
		toggleRect.width = 16f;

		// Ensure row is selected before using the toggle (usability)
        // 通过一个Rect对象,来判断是否有点击了这个区域
		if (evt.type == EventType.MouseDown && toggleRect.Contains(evt.mousePosition))
			SelectionClick(args.item, false);
		
		EditorGUI.BeginChangeCheck ();
		bool isStatic = EditorGUI.Toggle(toggleRect, gameObject.isStatic); 
		if (EditorGUI.EndChangeCheck ())
			gameObject.isStatic = isStatic;

		// Text 
        // 绘制名字,注释掉一下代码就看不到名字了
		base.RowGUI(args);
	}

    /// <summary>
    /// Selection
    /// 监听选择的改变
    /// </summary>
    /// <param name="selectedIds"> 选择到的 TreeViewItem 的 Id , 按 ctrl建或Shift建 一次选多个, selectIds 就会是对应的个数</param>
    protected override void SelectionChanged (IList<int> selectedIds)
	{
		Selection.instanceIDs = selectedIds.ToArray();
	}

    /// <summary>
    /// 处理 TreeViewItem 是否可以拖拽
    /// 父类中默认返回false, 所以需要拖拽功能就必须重写
    /// 如果返回为 true, 则需要 重写 SetupDragAndDrop 函数, 来实现拖拽
    /// </summary>
    /// <param name="args"> 选择要拖拽的TreeViewItem 的相关信息 </param>
    /// <returns></returns>
    protected override bool CanStartDrag (CanStartDragArgs args)
	{
		return true;
	}

    /// <summary>
    /// 在 CanStartDrag 函数返回 true 的情况下, 该函数才有用
    /// 实现拖拽功能
    /// </summary>
	protected override void SetupDragAndDrop (SetupDragAndDropArgs args)
	{
        //清除之前的数据
		DragAndDrop.PrepareStartDrag ();

        //调用 SortItemIDsInRowOrder函数,进行排序
        //规则是 根据 TreeViewItem 在视图中的位置进行排序, 越高的排在越前面的位置
        var sortedDraggedIDs = SortItemIDsInRowOrder (args.draggedItemIDs);

        //获取要拖拽的 object
		List<UnityObject> objList = new List<UnityObject> (sortedDraggedIDs.Count);
		foreach (var id in sortedDraggedIDs)
		{
			UnityObject obj = EditorUtility.InstanceIDToObject (id);
			if (obj != null)
				objList.Add (obj);
		}

        //设置要拖拽的对象
		DragAndDrop.objectReferences = objList.ToArray ();

		string title = objList.Count > 1 ? "<Multiple>" : objList[0].name;
		DragAndDrop.StartDrag (title);    //开始拖拽
	}


    /// <summary>
    /// 在 CanStartDrag 函数返回 true 的情况下, 该函数才有用
    /// 在 TreeView 视图中进行拖拽时, 该函数会被持续调用,
    /// 可以在函数中 接受 或 拒绝 该拖动
    /// </summary>
    protected override DragAndDropVisualMode HandleDragAndDrop (DragAndDropArgs args)
	{
		// First check if the dragged objects are GameObjects
		var draggedObjects = DragAndDrop.objectReferences;
		var transforms = new List<Transform> (draggedObjects.Length);
		foreach (var obj in draggedObjects)
		{
			var go = obj as GameObject;
			if (go == null)
			{
				return DragAndDropVisualMode.None;
			}

			transforms.Add (go.transform);
		}

		// Filter out any unnecessary transforms before the reparent operation
		RemoveItemsThatAreDescendantsFromOtherItems (transforms);

		// Reparent
		if (args.performDrop)
		{
			switch (args.dragAndDropPosition)
			{
				case DragAndDropPosition.UponItem:
				case DragAndDropPosition.BetweenItems:
					Transform parent = args.parentItem != null ? GetGameObject (args.parentItem.id).transform : null;

					if (!IsValidReparenting (parent, transforms))
						return DragAndDropVisualMode.None;

					foreach (var trans in transforms)
						trans.SetParent (parent);

					if (args.dragAndDropPosition == DragAndDropPosition.BetweenItems)
					{
						int insertIndex = args.insertAtIndex;
						for (int i = transforms.Count - 1; i >= 0; i--)
						{
							var transform = transforms[i];
							insertIndex = GetAdjustedInsertIndex (parent, transform, insertIndex);
							transform.SetSiblingIndex (insertIndex);
						}
					}
					break;

				case DragAndDropPosition.OutsideItems:
					foreach (var trans in transforms)
					{
						trans.SetParent (null); // make root when dragged to empty space in treeview
					}
					break;
				default:
					throw new ArgumentOutOfRangeException ();
			}

			Reload ();
			SetSelection (transforms.Select (t => t.gameObject.GetInstanceID ()).ToList (), TreeViewSelectionOptions.RevealAndFrame);
		}

		return DragAndDropVisualMode.Move;
	}

	int GetAdjustedInsertIndex (Transform parent, Transform transformToInsert, int insertIndex)
	{
		if (transformToInsert.parent == parent && transformToInsert.GetSiblingIndex () < insertIndex)
			return --insertIndex;
		return insertIndex;
	}

	bool IsValidReparenting (Transform parent, List<Transform> transformsToMove)
	{
		if (parent == null)
			return true;

		foreach (var transformToMove in transformsToMove)
		{
			if (transformToMove == parent)
				return false;

			if (IsHoveredAChildOfDragged (parent, transformToMove))
				return false;
		}

		return true;
	}


	bool IsHoveredAChildOfDragged (Transform hovered, Transform dragged)
	{
		Transform t = hovered.parent;
		while (t)
		{
			if (t == dragged)
				return true;
			t = t.parent;
		}
		return false;
	}


	// Returns true if there is an ancestor of transform in the transforms list
	static bool IsDescendantOf (Transform transform, List<Transform> transforms)
	{
		while (transform != null)
		{
			transform = transform.parent;
			if (transforms.Contains (transform))
				return true;
		}
		return false;
	}

	static void RemoveItemsThatAreDescendantsFromOtherItems (List<Transform> transforms)
	{
		transforms.RemoveAll (t => IsDescendantOf (t, transforms));
	}
}

}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published