void IDropHandler.OnDrop(PointerEventData eventData) { ((IPointerExitHandler)this).OnPointerExit(eventData); if (!hierarchy.CanReorganizeItems || hierarchy.IsInSearchMode) { return; } Transform droppedTransform = RuntimeInspectorUtils.GetAssignableObjectFromDraggedReferenceItem(eventData, typeof(Transform)) as Transform; if (!droppedTransform) { return; } int newSiblingIndex = -1; bool shouldFocusObjectInHierarchy = false; float contentYPos = pointerLastYPos + content.anchoredPosition.y; int dataIndex = (int)contentYPos / hierarchy.Skin.LineHeight; HierarchyData target = hierarchy.GetDataAt(dataIndex); if (target == null) { // Dropped object onto the blank space at the bottom of the Hierarchy if (droppedTransform.parent == null) { return; } droppedTransform.SetParent(null, true); shouldFocusObjectInHierarchy = true; } else { int insertDirection; float relativePosition = contentYPos % hierarchy.Skin.LineHeight; if (relativePosition < siblingIndexModificationArea) { insertDirection = -1; } else if (relativePosition > hierarchy.Skin.LineHeight - siblingIndexModificationArea) { insertDirection = 1; } else { insertDirection = 0; } // Inserting above/below a scene or pseudo-scene is a special case if (insertDirection != 0 && !(target is HierarchyDataTransform)) { if (insertDirection < 0 && dataIndex > 0) { // In Hierarchy AB, if inserting above B, then instead insert below A; it is easier for calculations HierarchyData _target = hierarchy.GetDataAt(dataIndex - 1); if (_target != null) { target = _target; insertDirection = 1; } } else if (insertDirection > 0 && dataIndex < hierarchy.ItemCount - 1) { // In Hierarchy AB, if inserting below A, then instead insert above B if B is a Transform; it is easier for calculations HierarchyData _target = hierarchy.GetDataAt(dataIndex + 1); if (_target != null && _target is HierarchyDataTransform) { target = _target; insertDirection = -1; } } } HierarchyDataRoot newScene = null; if (!(target is HierarchyDataTransform)) { // Dropped onto a scene or pseudo-scene newScene = (HierarchyDataRoot)target; } else { // Dropped onto a Transform Transform newParent = ((HierarchyDataTransform)target).BoundTransform; // Dropped onto itself, ignore if (!newParent || droppedTransform == newParent) { return; } if (insertDirection != 0) { if (insertDirection > 0 && target.Height > 1) { // Dropped below an expanded Transform, make dropped object a child of it newSiblingIndex = 0; } else if (target.Depth == 1 && target.Root is HierarchyDataRootPseudoScene) { // Dropped above or below a root pseudo-scene object, don't actually change the parent if (insertDirection < 0) { newSiblingIndex = ((HierarchyDataRootPseudoScene)target.Root).IndexOf(newParent); } else { newSiblingIndex = ((HierarchyDataRootPseudoScene)target.Root).IndexOf(newParent) + 1; } newParent = null; } else { // Dropped above or below a regular Transform, calculate target sibling index if (insertDirection < 0) { newSiblingIndex = newParent.GetSiblingIndex(); } else { newSiblingIndex = newParent.GetSiblingIndex() + 1; } // To be able to drop the object at that sibling index, object's parent must also be changed newParent = newParent.parent; // If we are only changing the sibling index of the dropped Transform and not the parent, then make sure // that the target sibling index won't be affected when the dropped Transform is shifted in the Hierarchy if (newParent == droppedTransform.parent && (newParent || (target.Root is HierarchyDataRootScene && ((HierarchyDataRootScene)target.Root).Scene == droppedTransform.gameObject.scene))) { if (newSiblingIndex > droppedTransform.GetSiblingIndex()) { newSiblingIndex--; } } } } if (!newParent) { newScene = target.Root; } else { if (!canDropParentOnChild) { // Avoid setting child object as parent of the parent object if (newParent.IsChildOf(droppedTransform)) { return; } } else { // First, set the child object's parent as dropped object's current parent so that // the dropped object can then become a child of the former child object Transform curr = newParent; while (curr.parent != null && curr.parent != droppedTransform) { curr = curr.parent; } if (curr.parent == droppedTransform) { if (droppedTransform.parent == null && target.Root is HierarchyDataRootPseudoScene) { // Dropped object was a root pseudo-scene object, swap the child and parent objects in the pseudo-scene, as well if (!canAddObjectsToPseudoScenes) { return; } HierarchyDataRootPseudoScene pseudoScene = (HierarchyDataRootPseudoScene)target.Root; pseudoScene.InsertChild(pseudoScene.IndexOf(newParent), curr); pseudoScene.RemoveChild(newParent); } int siblingIndex = droppedTransform.GetSiblingIndex(); curr.SetParent(droppedTransform.parent, true); curr.SetSiblingIndex(siblingIndex); shouldFocusObjectInHierarchy = true; } } droppedTransform.SetParent(newParent, true); } } if (newScene != null) { if (newScene is HierarchyDataRootPseudoScene) { if (!canAddObjectsToPseudoScenes) { return; } // Add object to pseudo-scene if (newSiblingIndex < 0) { ((HierarchyDataRootPseudoScene)newScene).AddChild(droppedTransform); } else { ((HierarchyDataRootPseudoScene)newScene).InsertChild(newSiblingIndex, droppedTransform); // Don't try to change the actual sibling index of the Transform newSiblingIndex = -1; target = newScene; } } else if (newScene is HierarchyDataRootScene) { if (droppedTransform.parent != null) { droppedTransform.SetParent(null, true); } // Change dropped object's scene Scene scene = ((HierarchyDataRootScene)newScene).Scene; if (droppedTransform.gameObject.scene != scene) { SceneManager.MoveGameObjectToScene(droppedTransform.gameObject, scene); } if (newSiblingIndex < 0) { // If object was dropped onto the scene, add it to the bottom of the scene newSiblingIndex = scene.rootCount + 1; shouldFocusObjectInHierarchy = true; } } } if (newSiblingIndex >= 0) { droppedTransform.SetSiblingIndex(newSiblingIndex); } } // Selecting the object in Hierarchy automatically expands collapsed parent entries and snaps the scroll view to the // selected object. However, this snapping can be distracting, so don't select the object unless it is necessary if (shouldFocusObjectInHierarchy || (newSiblingIndex < 0 && !target.IsExpanded)) { hierarchy.Select(droppedTransform, true); } else { hierarchy.Refresh(); } }
public HierarchyDataTransform FindTransform(Transform target, Transform nextInPath = null) { bool isInitSearch = nextInPath == null; if (isInitSearch) { nextInPath = target.root; ((HierarchyDataRoot)this).RefreshContent(); } int childIndex = IndexOf(nextInPath); if (childIndex < 0) { if (isInitSearch && this is HierarchyDataRootPseudoScene) { nextInPath = target; childIndex = IndexOf(nextInPath); while (childIndex < 0 && nextInPath != null) { nextInPath = nextInPath.parent; childIndex = IndexOf(nextInPath); } if (childIndex < 0) { return(null); } } else { return(null); } } if (!CanExpand) { return(null); } bool wasExpanded = IsExpanded; if (!wasExpanded) { IsExpanded = true; } HierarchyDataTransform childItem = children[childIndex]; if (childItem.BoundTransform == target) { return(childItem); } HierarchyDataTransform result = null; if (childItem.BoundTransform == nextInPath) { Transform next = target; Transform parent = next.parent; while (parent != null && parent != nextInPath) { next = parent; parent = next.parent; } if (parent != null) { result = childItem.FindTransform(target, next); } } if (result != null && result.m_depth < 0) { result = null; } if (result == null && !wasExpanded) { IsExpanded = false; } return(result); }