Beispiel #1
0
        private void OnEditorUpdate()
        {
            if (HasFocus)
            {
                if (!Input.IsPointerButtonHeld(PointerButton.Right))
                {
                    if (VirtualInput.IsButtonDown(EditorApplication.DuplicateKey))
                    {
                        DuplicateSelection();
                    }
                    else if (VirtualInput.IsButtonDown(EditorApplication.DeleteKey))
                    {
                        DeleteSelection();
                    }
                    else if (VirtualInput.IsButtonDown(toggleProfilerOverlayKey))
                    {
                        EditorSettings.SetBool(ProfilerOverlayActiveKey, !EditorSettings.GetBool(ProfilerOverlayActiveKey));
                    }
                    else if (VirtualInput.IsButtonDown(viewToolKey))
                    {
                        EditorApplication.ActiveSceneTool = SceneViewTool.View;
                    }
                    else if (VirtualInput.IsButtonDown(moveToolKey))
                    {
                        EditorApplication.ActiveSceneTool = SceneViewTool.Move;
                    }
                    else if (VirtualInput.IsButtonDown(rotateToolKey))
                    {
                        EditorApplication.ActiveSceneTool = SceneViewTool.Rotate;
                    }
                    else if (VirtualInput.IsButtonDown(scaleToolKey))
                    {
                        EditorApplication.ActiveSceneTool = SceneViewTool.Scale;
                    }
                }
            }

            // Refresh GUI buttons if needed (in case someones changes the values from script)
            if (editorSettingsHash != EditorSettings.Hash)
            {
                UpdateButtonStates();
                UpdateProfilerOverlay();
                editorSettingsHash = EditorSettings.Hash;
            }

            // Update scene view handles and selection
            sceneGizmos.Draw();
            sceneGrid.Draw();

            bool handleActive = sceneHandles.IsActive() || sceneAxesGUI.IsActive();

            Vector2I scenePos;
            bool     inBounds   = ScreenToScenePos(Input.PointerPosition, out scenePos);
            bool     dragResult = false;

            if (Input.IsPointerButtonUp(PointerButton.Left))
            {
                dragResult = EndDragSelection();
                if (sceneHandles.IsActive())
                {
                    sceneHandles.ClearSelection();
                }

                if (sceneAxesGUI.IsActive())
                {
                    sceneAxesGUI.ClearSelection();
                }
            }
            else if (Input.IsPointerButtonDown(PointerButton.Left))
            {
                mouseDownPosition = scenePos;
            }

            bool draggedOver = DragDrop.DragInProgress || DragDrop.DropInProgress;

            draggedOver &= IsPointerHovering && inBounds && DragDrop.Type == DragDropType.Resource;

            if (draggedOver)
            {
                if (DragDrop.DropInProgress)
                {
                    dragActive = false;
                    if (draggedSO != null)
                    {
                        Selection.SceneObject = draggedSO;
                        EditorApplication.SetSceneDirty();
                    }

                    draggedSO = null;
                }
                else
                {
                    if (!dragActive)
                    {
                        dragActive = true;

                        ResourceDragDropData dragData = (ResourceDragDropData)DragDrop.Data;

                        string[] draggedPaths = dragData.Paths;

                        for (int i = 0; i < draggedPaths.Length; i++)
                        {
                            ResourceMeta meta = ProjectLibrary.GetMeta(draggedPaths[i]);
                            if (meta != null)
                            {
                                if (meta.ResType == ResourceType.Mesh)
                                {
                                    if (!string.IsNullOrEmpty(draggedPaths[i]))
                                    {
                                        string meshName = Path.GetFileNameWithoutExtension(draggedPaths[i]);
                                        draggedSO = UndoRedo.CreateSO(meshName, "Created a new Renderable \"" + meshName + "\"");
                                        Mesh mesh = ProjectLibrary.Load <Mesh>(draggedPaths[i]);

                                        Renderable renderable = draggedSO.AddComponent <Renderable>();
                                        renderable.Mesh = mesh;
                                        if (mesh != null)
                                        {
                                            draggedSOOffset = mesh.Bounds.Box.Center;
                                        }
                                        else
                                        {
                                            draggedSOOffset = Vector3.Zero;
                                        }
                                    }

                                    break;
                                }
                                else if (meta.ResType == ResourceType.Prefab)
                                {
                                    if (!string.IsNullOrEmpty(draggedPaths[i]))
                                    {
                                        Prefab prefab = ProjectLibrary.Load <Prefab>(draggedPaths[i]);
                                        draggedSO = UndoRedo.Instantiate(prefab, "Instantiating " + prefab.Name);

                                        if (draggedSO != null)
                                        {
                                            AABox draggedObjBounds = EditorUtility.CalculateBounds(draggedSO);
                                            draggedSOOffset = draggedObjBounds.Center;
                                        }
                                        else
                                        {
                                            draggedSOOffset = Vector3.Zero;
                                        }
                                    }

                                    break;
                                }
                            }
                        }
                    }

                    if (draggedSO != null)
                    {
                        if (Input.IsButtonHeld(ButtonCode.Space))
                        {
                            SnapData snapData;
                            sceneSelection.Snap(scenePos, out snapData, new SceneObject[] { draggedSO });

                            Quaternion q = Quaternion.FromToRotation(Vector3.YAxis, snapData.normal);
                            draggedSO.Position = snapData.position;
                            draggedSO.Rotation = q;
                        }
                        else
                        {
                            Ray worldRay = camera.ScreenPointToRay(scenePos);
                            draggedSO.Position = worldRay * DefaultPlacementDepth - draggedSOOffset;
                        }
                    }
                }

                return;
            }
            else
            {
                if (dragActive)
                {
                    dragActive = false;

                    if (draggedSO != null)
                    {
                        draggedSO.Destroy();
                        draggedSO = null;
                    }
                }
            }

            if (HasContentFocus || IsPointerHovering)
            {
                cameraController.EnableInput(true);

                if (inBounds && HasContentFocus)
                {
                    if (Input.IsPointerButtonDown(PointerButton.Left))
                    {
                        Rect2I sceneAxesGUIBounds = new Rect2I(Width - HandleAxesGUISize - HandleAxesGUIPaddingX,
                                                               HandleAxesGUIPaddingY, HandleAxesGUISize, HandleAxesGUISize);

                        if (sceneAxesGUIBounds.Contains(scenePos))
                        {
                            sceneAxesGUI.TrySelect(scenePos);
                        }
                        else
                        {
                            sceneHandles.TrySelect(scenePos);
                        }
                    }
                    else if (Input.IsPointerButtonHeld(PointerButton.Left) && !handleActive && !dragActive &&
                             draggedSO == null && scenePos != mouseDownPosition)
                    {
                        if (isDraggingSelection)
                        {
                            UpdateDragSelection(scenePos);
                        }
                        else
                        {
                            StartDragSelection(scenePos);
                        }
                    }
                    else if (Input.IsPointerButtonUp(PointerButton.Left))
                    {
                        if (!handleActive && !dragActive && !dragResult)
                        {
                            bool ctrlHeld = Input.IsButtonHeld(ButtonCode.LeftControl) ||
                                            Input.IsButtonHeld(ButtonCode.RightControl);

                            sceneSelection.PickObject(scenePos, ctrlHeld, new SceneObject[] { draggedSO });
                        }
                    }
                }
            }
            else
            {
                cameraController.EnableInput(false);
            }

            SceneHandles.BeginInput();
            sceneHandles.UpdateInput(scenePos, Input.PointerDelta);
            sceneHandles.Draw();

            sceneAxesGUI.UpdateInput(scenePos);
            sceneAxesGUI.Draw();
            SceneHandles.EndInput();

            sceneSelection.Draw();

            UpdateGridMode();

            if (VirtualInput.IsButtonDown(frameKey))
            {
                cameraController.FrameSelected();
            }
        }
        /// <summary>
        /// Updates contents of the scene object specific fields (name, position, rotation, etc.)
        /// </summary>
        /// <param name="forceUpdate">If true, the GUI elements will be updated regardless of whether a change was
        ///                           detected or not.</param>
        private void RefreshSceneObjectFields(bool forceUpdate)
        {
            if (activeSO == null)
            {
                return;
            }

            soNameInput.Text     = activeSO.Name;
            soActiveToggle.Value = activeSO.Active;
            soMobility.Value     = (ulong)activeSO.Mobility;

            SceneObject prefabParent = PrefabUtility.GetPrefabParent(activeSO);

            // Ignore prefab parent if scene root, we only care for non-root prefab instances
            bool hasPrefab = prefabParent != null && prefabParent.Parent != null;

            if (soHasPrefab != hasPrefab || forceUpdate)
            {
                int numChildren = soPrefabLayout.ChildCount;
                for (int i = 0; i < numChildren; i++)
                {
                    soPrefabLayout.GetChild(0).Destroy();
                }

                GUILabel prefabLabel = new GUILabel(new LocEdString("Prefab"), GUIOption.FixedWidth(50));
                soPrefabLayout.AddElement(prefabLabel);

                if (hasPrefab)
                {
                    GUIButton btnApplyPrefab  = new GUIButton(new LocEdString("Apply"), GUIOption.FixedWidth(60));
                    GUIButton btnRevertPrefab = new GUIButton(new LocEdString("Revert"), GUIOption.FixedWidth(60));
                    GUIButton btnBreakPrefab  = new GUIButton(new LocEdString("Break"), GUIOption.FixedWidth(60));

                    btnApplyPrefab.OnClick += () =>
                    {
                        PrefabUtility.ApplyPrefab(activeSO);
                    };
                    btnRevertPrefab.OnClick += () =>
                    {
                        UndoRedo.RecordSO(activeSO, true, "Reverting \"" + activeSO.Name + "\" to prefab.");

                        PrefabUtility.RevertPrefab(activeSO);
                        EditorApplication.SetSceneDirty();
                    };
                    btnBreakPrefab.OnClick += () =>
                    {
                        UndoRedo.BreakPrefab(activeSO, "Breaking prefab link for " + activeSO.Name);

                        EditorApplication.SetSceneDirty();
                    };

                    soPrefabLayout.AddElement(btnApplyPrefab);
                    soPrefabLayout.AddElement(btnRevertPrefab);
                    soPrefabLayout.AddElement(btnBreakPrefab);
                }
                else
                {
                    GUILabel noPrefabLabel = new GUILabel("None");
                    soPrefabLayout.AddElement(noPrefabLabel);
                }

                soHasPrefab = hasPrefab;
            }

            Vector3 position;
            Vector3 angles;

            if (EditorApplication.ActiveCoordinateMode == HandleCoordinateMode.World)
            {
                position = activeSO.Position;
                angles   = activeSO.Rotation.ToEuler();
            }
            else
            {
                position = activeSO.LocalPosition;
                angles   = activeSO.LocalRotation.ToEuler();
            }

            Vector3 scale = activeSO.LocalScale;

            if (!soPosX.HasInputFocus)
            {
                soPosX.Value = position.x;
            }

            if (!soPosY.HasInputFocus)
            {
                soPosY.Value = position.y;
            }

            if (!soPosZ.HasInputFocus)
            {
                soPosZ.Value = position.z;
            }

            if (!soRotX.HasInputFocus)
            {
                soRotX.Value = angles.x;
            }

            if (!soRotY.HasInputFocus)
            {
                soRotY.Value = angles.y;
            }

            if (!soRotZ.HasInputFocus)
            {
                soRotZ.Value = angles.z;
            }

            if (!soScaleX.HasInputFocus)
            {
                soScaleX.Value = scale.x;
            }

            if (!soScaleY.HasInputFocus)
            {
                soScaleY.Value = scale.y;
            }

            if (!soScaleZ.HasInputFocus)
            {
                soScaleZ.Value = scale.z;
            }
        }
        private void OnEditorUpdate()
        {
            if (currentType == InspectorType.SceneObject)
            {
                Component[] allComponents   = activeSO.GetComponents();
                bool        requiresRebuild = allComponents.Length != inspectorComponents.Count;

                if (!requiresRebuild)
                {
                    for (int i = 0; i < inspectorComponents.Count; i++)
                    {
                        if (inspectorComponents[i].instanceId != allComponents[i].InstanceId)
                        {
                            requiresRebuild = true;
                            break;
                        }
                    }
                }

                if (requiresRebuild)
                {
                    SceneObject so = activeSO;
                    Clear();
                    SetObjectToInspect(so);
                }
                else
                {
                    RefreshSceneObjectFields(false);

                    InspectableState componentModifyState = InspectableState.NotModified;
                    for (int i = 0; i < inspectorComponents.Count; i++)
                    {
                        componentModifyState |= inspectorComponents[i].inspector.Refresh();
                    }

                    if (componentModifyState.HasFlag(InspectableState.ModifyInProgress))
                    {
                        EditorApplication.SetSceneDirty();
                    }

                    modifyState |= componentModifyState;
                }
            }
            else if (currentType == InspectorType.Resource)
            {
                inspectorResource.inspector.Refresh();
            }

            // Detect drag and drop
            bool isValidDrag = false;

            if (activeSO != null)
            {
                if ((DragDrop.DragInProgress || DragDrop.DropInProgress) && DragDrop.Type == DragDropType.Resource)
                {
                    Vector2I windowPos     = ScreenToWindowPos(Input.PointerPosition);
                    Vector2I scrollPos     = windowPos;
                    Rect2I   contentBounds = inspectorLayout.Bounds;
                    scrollPos.x -= contentBounds.x;
                    scrollPos.y -= contentBounds.y;

                    bool   isInBounds = false;
                    Rect2I dropArea   = new Rect2I();
                    foreach (var bounds in dropAreas)
                    {
                        if (bounds.Contains(scrollPos))
                        {
                            isInBounds = true;
                            dropArea   = bounds;
                            break;
                        }
                    }

                    Type draggedComponentType = null;
                    if (isInBounds)
                    {
                        ResourceDragDropData dragData = DragDrop.Data as ResourceDragDropData;
                        if (dragData != null)
                        {
                            foreach (var resPath in dragData.Paths)
                            {
                                ResourceMeta meta = ProjectLibrary.GetMeta(resPath);
                                if (meta != null)
                                {
                                    if (meta.ResType == ResourceType.ScriptCode)
                                    {
                                        ScriptCode scriptFile = ProjectLibrary.Load <ScriptCode>(resPath);

                                        if (scriptFile != null)
                                        {
                                            Type[] scriptTypes = scriptFile.Types;
                                            foreach (var type in scriptTypes)
                                            {
                                                if (type.IsSubclassOf(typeof(Component)))
                                                {
                                                    draggedComponentType = type;
                                                    isValidDrag          = true;
                                                    break;
                                                }
                                            }

                                            if (draggedComponentType != null)
                                            {
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (isValidDrag)
                    {
                        scrollAreaHighlight.Bounds = dropArea;

                        if (DragDrop.DropInProgress)
                        {
                            activeSO.AddComponent(draggedComponentType);

                            modifyState = InspectableState.Modified;
                            EditorApplication.SetSceneDirty();
                        }
                    }
                }
            }

            if (scrollAreaHighlight != null)
            {
                scrollAreaHighlight.Active = isValidDrag;
            }
        }
Beispiel #4
0
        private void OnEditorUpdate()
        {
            if (HasFocus)
            {
                if (!Input.IsPointerButtonHeld(PointerButton.Right))
                {
                    if (VirtualInput.IsButtonDown(toggleProfilerOverlayKey))
                        EditorSettings.SetBool(ProfilerOverlayActiveKey, !EditorSettings.GetBool(ProfilerOverlayActiveKey));

                    if (VirtualInput.IsButtonDown(viewToolKey))
                        EditorApplication.ActiveSceneTool = SceneViewTool.View;

                    if (VirtualInput.IsButtonDown(moveToolKey))
                        EditorApplication.ActiveSceneTool = SceneViewTool.Move;

                    if (VirtualInput.IsButtonDown(rotateToolKey))
                        EditorApplication.ActiveSceneTool = SceneViewTool.Rotate;

                    if (VirtualInput.IsButtonDown(scaleToolKey))
                        EditorApplication.ActiveSceneTool = SceneViewTool.Scale;

                    if (VirtualInput.IsButtonDown(duplicateKey))
                    {
                        SceneObject[] selectedObjects = Selection.SceneObjects;
                        CleanDuplicates(ref selectedObjects);

                        if (selectedObjects.Length > 0)
                        {
                            String message;
                            if (selectedObjects.Length == 1)
                                message = "Duplicated " + selectedObjects[0].Name;
                            else
                                message = "Duplicated " + selectedObjects.Length + " elements";

                            UndoRedo.CloneSO(selectedObjects, message);
                            EditorApplication.SetSceneDirty();
                        }
                    }

                    if (VirtualInput.IsButtonDown(deleteKey))
                    {
                        SceneObject[] selectedObjects = Selection.SceneObjects;
                        CleanDuplicates(ref selectedObjects);

                        if (selectedObjects.Length > 0)
                        {
                            foreach (var so in selectedObjects)
                            {
                                string message = "Deleted " + so.Name;
                                UndoRedo.DeleteSO(so, message);
                            }

                            EditorApplication.SetSceneDirty();
                        }
                    }
                }
            }

            // Refresh GUI buttons if needed (in case someones changes the values from script)
            if (editorSettingsHash != EditorSettings.Hash)
            {
                UpdateButtonStates();
                UpdateProfilerOverlay();
                editorSettingsHash = EditorSettings.Hash;
            }

            // Update scene view handles and selection
            sceneGizmos.Draw();
            sceneGrid.Draw();

            bool handleActive = false;
            if (Input.IsPointerButtonUp(PointerButton.Left))
            {
                if (sceneHandles.IsActive())
                {
                    sceneHandles.ClearSelection();
                    handleActive = true;
                }

                if (sceneAxesGUI.IsActive())
                {
                    sceneAxesGUI.ClearSelection();
                    handleActive = true;
                }
            }

            Vector2I scenePos;
            bool inBounds = ScreenToScenePos(Input.PointerPosition, out scenePos);

            bool draggedOver = DragDrop.DragInProgress || DragDrop.DropInProgress;
            draggedOver &= IsPointerHovering && inBounds && DragDrop.Type == DragDropType.Resource;

            if (draggedOver)
            {
                if (DragDrop.DropInProgress)
                {
                    dragActive = false;

                    if (draggedSO != null)
                    {
                        Selection.SceneObject = draggedSO;
                        EditorApplication.SetSceneDirty();
                    }

                    draggedSO = null;
                }
                else
                {
                    if (!dragActive)
                    {
                        dragActive = true;

                        ResourceDragDropData dragData = (ResourceDragDropData)DragDrop.Data;

                        string[] draggedPaths = dragData.Paths;

                        for (int i = 0; i < draggedPaths.Length; i++)
                        {
                            LibraryEntry entry = ProjectLibrary.GetEntry(draggedPaths[i]);
                            if (entry != null && entry.Type == LibraryEntryType.File)
                            {
                                FileEntry fileEntry = (FileEntry) entry;
                                if (fileEntry.ResType == ResourceType.Mesh)
                                {
                                    if (!string.IsNullOrEmpty(draggedPaths[i]))
                                    {
                                        string meshName = Path.GetFileNameWithoutExtension(draggedPaths[i]);
                                        draggedSO = UndoRedo.CreateSO(meshName, "Created a new Renderable \"" + meshName + "\"");
                                        Mesh mesh = ProjectLibrary.Load<Mesh>(draggedPaths[i]);

                                        Renderable renderable = draggedSO.AddComponent<Renderable>();
                                        renderable.Mesh = mesh;
                                    }

                                    break;
                                }
                                else if (fileEntry.ResType == ResourceType.Prefab)
                                {
                                    if (!string.IsNullOrEmpty(draggedPaths[i]))
                                    {
                                        Prefab prefab = ProjectLibrary.Load<Prefab>(draggedPaths[i]);
                                        draggedSO = UndoRedo.Instantiate(prefab, "Instantiating " + prefab.Name);
                                    }

                                    break;
                                }
                            }
                        }
                    }

                    if (draggedSO != null)
                    {
                        Ray worldRay = camera.ScreenToWorldRay(scenePos);
                        draggedSO.Position = worldRay*DefaultPlacementDepth;
                    }
                }

                return;
            }
            else
            {
                if (dragActive)
                {
                    dragActive = false;

                    if (draggedSO != null)
                    {
                        draggedSO.Destroy();
                        draggedSO = null;
                    }
                }
            }

            if (HasFocus)
            {
                cameraController.EnableInput(true);

                if (inBounds)
                {
                    if (Input.IsPointerButtonDown(PointerButton.Left))
                    {
                        Rect2I sceneAxesGUIBounds = new Rect2I(Width - HandleAxesGUISize - HandleAxesGUIPaddingX, 
                            HandleAxesGUIPaddingY, HandleAxesGUISize, HandleAxesGUISize);

                        if (sceneAxesGUIBounds.Contains(scenePos))
                            sceneAxesGUI.TrySelect(scenePos);
                        else
                            sceneHandles.TrySelect(scenePos);
                    }
                    else if (Input.IsPointerButtonUp(PointerButton.Left))
                    {
                        if (!handleActive)
                        {
                            bool ctrlHeld = Input.IsButtonHeld(ButtonCode.LeftControl) ||
                                            Input.IsButtonHeld(ButtonCode.RightControl);

                            sceneSelection.PickObject(scenePos, ctrlHeld);
                        }
                    }
                }
            }
            else
                cameraController.EnableInput(false);

            SceneHandles.BeginInput();
            sceneHandles.UpdateInput(scenePos, Input.PointerDelta);
            sceneHandles.Draw();

            sceneAxesGUI.UpdateInput(scenePos);
            sceneAxesGUI.Draw();
            SceneHandles.EndInput();

            sceneSelection.Draw();

            UpdateGridMode();

            if (VirtualInput.IsButtonDown(frameKey))
                cameraController.FrameSelected();
        }
 /// <summary>
 /// Triggered by the runtime when the scene is modified from the native scene tree view.
 /// </summary>
 private void Internal_DoOnModified()
 {
     EditorApplication.SetSceneDirty();
 }
Beispiel #6
0
        /// <inheritdoc/>
        protected internal override void PostInput()
        {
            if (activeHandle != null)
            {
                if (activeHandle.IsDragged())
                {
                    if (!isDragged)
                    {
                        isDragged = true;

                        SceneObject[] selectedSceneObjects = Selection.SceneObjects;
                        activeSelection = new HandledObject[selectedSceneObjects.Length];
                        for (int i = 0; i < selectedSceneObjects.Length; i++)
                        {
                            activeSelection[i] = new HandledObject(selectedSceneObjects[i]);
                        }

                        initialHandlePosition = activeHandle.Position;
                        initialHandleRotation = activeHandle.Rotation;
                    }
                }
                else
                {
                    isDragged       = false;
                    activeSelection = null;
                }

                activeHandle.PostInput();

                if (activeHandle.IsDragged())
                {
                    switch (activeHandleType)
                    {
                    case SceneViewTool.Move:
                        MoveHandle moveHandle = (MoveHandle)activeHandle;

                        foreach (var selectedObj in activeSelection)
                        {
                            selectedObj.so.LocalPosition = selectedObj.initialPosition + moveHandle.Delta;
                        }

                        break;

                    case SceneViewTool.Rotate:
                    {
                        RotateHandle rotateHandle = (RotateHandle)activeHandle;

                        // Make sure we transform relative to the handle position
                        SceneObject temporarySO = new SceneObject("Temp");
                        temporarySO.Position      = initialHandlePosition;
                        temporarySO.LocalRotation = initialHandleRotation;

                        SceneObject[] originalParents = new SceneObject[activeSelection.Length];
                        for (int i = 0; i < activeSelection.Length; i++)
                        {
                            originalParents[i] = activeSelection[i].so.Parent;
                            activeSelection[i].so.LocalPosition = activeSelection[i].initialPosition;
                            activeSelection[i].so.LocalRotation = activeSelection[i].initialRotation;
                            activeSelection[i].so.Parent        = temporarySO;
                        }

                        temporarySO.LocalRotation *= rotateHandle.Delta;

                        for (int i = 0; i < activeSelection.Length; i++)
                        {
                            activeSelection[i].so.Parent = originalParents[i];
                        }

                        temporarySO.Destroy();
                    }
                    break;

                    case SceneViewTool.Scale:
                    {
                        ScaleHandle scaleHandle = (ScaleHandle)activeHandle;

                        // Make sure we transform relative to the handle position
                        SceneObject temporarySO = new SceneObject("Temp");
                        temporarySO.Position = activeHandle.Position;

                        SceneObject[] originalParents = new SceneObject[activeSelection.Length];
                        for (int i = 0; i < activeSelection.Length; i++)
                        {
                            originalParents[i] = activeSelection[i].so.Parent;
                            activeSelection[i].so.LocalPosition = activeSelection[i].initialPosition;
                            activeSelection[i].so.LocalRotation = activeSelection[i].initialRotation;
                            activeSelection[i].so.LocalScale    = activeSelection[i].initialScale;
                            activeSelection[i].so.Parent        = temporarySO;
                        }

                        temporarySO.LocalScale += scaleHandle.Delta;

                        for (int i = 0; i < activeSelection.Length; i++)
                        {
                            activeSelection[i].so.Parent = originalParents[i];
                        }

                        temporarySO.Destroy();
                    }
                    break;
                    }

                    EditorApplication.SetSceneDirty();
                }
            }
            else
            {
                isDragged       = false;
                activeSelection = null;
            }
        }
        /// <summary>
        /// Updates contents of the scene object specific fields (name, position, rotation, etc.)
        /// </summary>
        /// <param name="forceUpdate">If true, the GUI elements will be updated regardless of whether a change was
        ///                           detected or not.</param>
        private void RefreshSceneObjectFields(bool forceUpdate)
        {
            if (activeSO == null)
            {
                return;
            }

            soNameInput.Text     = activeSO.Name;
            soActiveToggle.Value = activeSO.Active;
            soMobility.Value     = (ulong)activeSO.Mobility;

            SceneObject prefabParent = PrefabUtility.GetPrefabParent(activeSO);

            // Ignore prefab parent if scene root, we only care for non-root prefab instances
            bool hasPrefab = prefabParent != null && prefabParent.Parent != null;

            if (soHasPrefab != hasPrefab || forceUpdate)
            {
                int numChildren = soPrefabLayout.ChildCount;
                for (int i = 0; i < numChildren; i++)
                {
                    soPrefabLayout.GetChild(0).Destroy();
                }

                GUILabel prefabLabel = new GUILabel(new LocEdString("Prefab"), GUIOption.FixedWidth(50));
                soPrefabLayout.AddElement(prefabLabel);

                if (hasPrefab)
                {
                    GUIButton btnApplyPrefab  = new GUIButton(new LocEdString("Apply"), GUIOption.FixedWidth(60));
                    GUIButton btnRevertPrefab = new GUIButton(new LocEdString("Revert"), GUIOption.FixedWidth(60));
                    GUIButton btnBreakPrefab  = new GUIButton(new LocEdString("Break"), GUIOption.FixedWidth(60));

                    btnApplyPrefab.OnClick += () =>
                    {
                        PrefabUtility.ApplyPrefab(activeSO);
                    };
                    btnRevertPrefab.OnClick += () =>
                    {
                        UndoRedo.RecordSO(activeSO, true, "Reverting \"" + activeSO.Name + "\" to prefab.");

                        PrefabUtility.RevertPrefab(activeSO);
                        EditorApplication.SetSceneDirty();
                    };
                    btnBreakPrefab.OnClick += () =>
                    {
                        UndoRedo.BreakPrefab(activeSO, "Breaking prefab link for " + activeSO.Name);

                        EditorApplication.SetSceneDirty();
                    };

                    soPrefabLayout.AddElement(btnApplyPrefab);
                    soPrefabLayout.AddElement(btnRevertPrefab);
                    soPrefabLayout.AddElement(btnBreakPrefab);
                }
                else
                {
                    GUILabel noPrefabLabel = new GUILabel("None");
                    soPrefabLayout.AddElement(noPrefabLabel);
                }

                soHasPrefab = hasPrefab;
            }

            Vector3    position;
            Quaternion rotation;

            if (EditorApplication.ActiveCoordinateMode == HandleCoordinateMode.World)
            {
                position = activeSO.Position;
                rotation = activeSO.Rotation;
            }
            else
            {
                position = activeSO.LocalPosition;
                rotation = activeSO.LocalRotation;
            }

            Vector3 scale = activeSO.LocalScale;

            if (!soPos.HasInputFocus)
            {
                soPos.Value = position;
            }

            // Avoid updating the rotation unless actually changed externally, since switching back and forth between
            // quaternion and euler angles can cause weird behavior
            if (!soRot.HasInputFocus && rotation != lastRotation)
            {
                soRot.Value  = rotation.ToEuler();
                lastRotation = rotation;
            }

            if (!soScale.HasInputFocus)
            {
                soScale.Value = scale;
            }
        }
        private void RebuildGUI()
        {
            GUI.Clear();
            guiCurveEditor  = null;
            guiFieldDisplay = null;

            if (selectedSO == null)
            {
                GUILabel warningLbl = new GUILabel(new LocEdString("Select an object to animate in the Hierarchy or Scene windows."));

                GUILayoutY vertLayout = GUI.AddLayoutY();
                vertLayout.AddFlexibleSpace();
                GUILayoutX horzLayout = vertLayout.AddLayoutX();
                vertLayout.AddFlexibleSpace();

                horzLayout.AddFlexibleSpace();
                horzLayout.AddElement(warningLbl);
                horzLayout.AddFlexibleSpace();

                return;
            }

            // Top button row
            GUIContent playIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.Play),
                                                 new LocEdString("Play"));
            GUIContent recordIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.Record),
                                                   new LocEdString("Record"));

            GUIContent prevFrameIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.FrameBack),
                                                      new LocEdString("Previous frame"));
            GUIContent nextFrameIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.FrameForward),
                                                      new LocEdString("Next frame"));

            GUIContent addKeyframeIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.AddKeyframe),
                                                        new LocEdString("Add keyframe"));
            GUIContent addEventIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.AddEvent),
                                                     new LocEdString("Add event"));

            GUIContent optionsIcon = new GUIContent(EditorBuiltin.GetLibraryWindowIcon(LibraryWindowIcon.Options),
                                                    new LocEdString("Options"));

            playButton   = new GUIButton(playIcon);
            recordButton = new GUIButton(recordIcon);

            prevFrameButton = new GUIButton(prevFrameIcon);
            frameInputField = new GUIIntField();
            nextFrameButton = new GUIButton(nextFrameIcon);

            addKeyframeButton = new GUIButton(addKeyframeIcon);
            addEventButton    = new GUIButton(addEventIcon);

            optionsButton = new GUIButton(optionsIcon);

            playButton.OnClick += () =>
            {
                // TODO
                // - Record current state of the scene object hierarchy
                // - Evaluate all curves manually and update them
                // - On end, restore original values of the scene object hierarchy
            };

            recordButton.OnClick += () =>
            {
                // TODO
                // - Every frame read back current values of all the current curve's properties and assign it to the current frame
            };

            prevFrameButton.OnClick += () =>
            {
                SetCurrentFrame(currentFrameIdx - 1);
            };

            frameInputField.OnChanged += SetCurrentFrame;

            nextFrameButton.OnClick += () =>
            {
                SetCurrentFrame(currentFrameIdx + 1);
            };

            addKeyframeButton.OnClick += () =>
            {
                guiCurveEditor.AddKeyFrameAtMarker();
            };

            addEventButton.OnClick += () =>
            {
                guiCurveEditor.AddEventAtMarker();
            };

            optionsButton.OnClick += () =>
            {
                Vector2I         openPosition = ScreenToWindowPos(Input.PointerPosition);
                AnimationOptions dropDown     = DropDownWindow.Open <AnimationOptions>(this, openPosition);
                dropDown.Initialize(this);
            };

            // Property buttons
            addPropertyBtn = new GUIButton(new LocEdString("Add property"));
            delPropertyBtn = new GUIButton(new LocEdString("Delete selected"));

            addPropertyBtn.OnClick += () =>
            {
                Action openPropertyWindow = () =>
                {
                    Vector2I             windowPos      = ScreenToWindowPos(Input.PointerPosition);
                    FieldSelectionWindow fieldSelection = DropDownWindow.Open <FieldSelectionWindow>(this, windowPos);
                    fieldSelection.OnFieldSelected += OnFieldAdded;
                };

                if (clipInfo.clip == null)
                {
                    LocEdString title   = new LocEdString("Warning");
                    LocEdString message =
                        new LocEdString("Selected object doesn't have an animation clip assigned. Would you like to create" +
                                        " a new animation clip?");

                    DialogBox.Open(title, message, DialogBox.Type.YesNoCancel, type =>
                    {
                        if (type == DialogBox.ResultType.Yes)
                        {
                            string clipSavePath;
                            if (BrowseDialog.SaveFile(ProjectLibrary.ResourceFolder, "*.asset", out clipSavePath))
                            {
                                clipSavePath = Path.ChangeExtension(clipSavePath, ".asset");

                                AnimationClip newClip = new AnimationClip();

                                ProjectLibrary.Create(newClip, clipSavePath);
                                LoadAnimClip(newClip);

                                Animation animation = selectedSO.GetComponent <Animation>();
                                if (animation == null)
                                {
                                    animation = selectedSO.AddComponent <Animation>();
                                }

                                animation.DefaultClip = newClip;
                                EditorApplication.SetSceneDirty();

                                openPropertyWindow();
                            }
                        }
                    });
                }
                else
                {
                    if (clipInfo.isImported)
                    {
                        LocEdString title   = new LocEdString("Warning");
                        LocEdString message =
                            new LocEdString("You cannot add/edit/remove curves from animation clips that" +
                                            " are imported from an external file.");

                        DialogBox.Open(title, message, DialogBox.Type.OK);
                    }
                    else
                    {
                        openPropertyWindow();
                    }
                }
            };

            delPropertyBtn.OnClick += () =>
            {
                if (clipInfo.clip == null)
                {
                    return;
                }

                if (clipInfo.isImported)
                {
                    LocEdString title   = new LocEdString("Warning");
                    LocEdString message =
                        new LocEdString("You cannot add/edit/remove curves from animation clips that" +
                                        " are imported from an external file.");

                    DialogBox.Open(title, message, DialogBox.Type.OK);
                }
                else
                {
                    LocEdString title   = new LocEdString("Warning");
                    LocEdString message = new LocEdString("Are you sure you want to remove all selected fields?");

                    DialogBox.Open(title, message, DialogBox.Type.YesNo, x =>
                    {
                        if (x == DialogBox.ResultType.Yes)
                        {
                            RemoveSelectedFields();
                        }
                    });
                }
            };

            GUIPanel mainPanel       = GUI.AddPanel();
            GUIPanel backgroundPanel = GUI.AddPanel(1);

            GUILayout mainLayout = mainPanel.AddLayoutY();

            buttonLayout = mainLayout.AddLayoutX();
            buttonLayout.AddSpace(5);
            buttonLayout.AddElement(playButton);
            buttonLayout.AddElement(recordButton);
            buttonLayout.AddSpace(5);
            buttonLayout.AddElement(prevFrameButton);
            buttonLayout.AddElement(frameInputField);
            buttonLayout.AddElement(nextFrameButton);
            buttonLayout.AddSpace(5);
            buttonLayout.AddElement(addKeyframeButton);
            buttonLayout.AddElement(addEventButton);
            buttonLayout.AddSpace(5);
            buttonLayout.AddElement(optionsButton);
            buttonLayout.AddFlexibleSpace();

            buttonLayoutHeight = playButton.Bounds.height;

            GUITexture buttonBackground = new GUITexture(null, EditorStyles.HeaderBackground);

            buttonBackground.Bounds = new Rect2I(0, 0, Width, buttonLayoutHeight);
            backgroundPanel.AddElement(buttonBackground);

            GUILayout contentLayout      = mainLayout.AddLayoutX();
            GUILayout fieldDisplayLayout = contentLayout.AddLayoutY(GUIOption.FixedWidth(FIELD_DISPLAY_WIDTH));

            guiFieldDisplay = new GUIAnimFieldDisplay(fieldDisplayLayout, FIELD_DISPLAY_WIDTH,
                                                      Height - buttonLayoutHeight * 2, selectedSO);
            guiFieldDisplay.OnEntrySelected += OnFieldSelected;

            GUILayout bottomButtonLayout = fieldDisplayLayout.AddLayoutX();

            bottomButtonLayout.AddElement(addPropertyBtn);
            bottomButtonLayout.AddElement(delPropertyBtn);

            horzScrollBar = new GUIResizeableScrollBarH();
            horzScrollBar.OnScrollOrResize += OnHorzScrollOrResize;

            vertScrollBar = new GUIResizeableScrollBarV();
            vertScrollBar.OnScrollOrResize += OnVertScrollOrResize;

            GUITexture separator = new GUITexture(null, EditorStyles.Separator, GUIOption.FixedWidth(3));

            contentLayout.AddElement(separator);

            GUILayout curveLayout         = contentLayout.AddLayoutY();
            GUILayout curveLayoutHorz     = curveLayout.AddLayoutX();
            GUILayout horzScrollBarLayout = curveLayout.AddLayoutX();

            horzScrollBarLayout.AddElement(horzScrollBar);
            horzScrollBarLayout.AddFlexibleSpace();

            editorPanel = curveLayoutHorz.AddPanel();
            curveLayoutHorz.AddElement(vertScrollBar);
            curveLayoutHorz.AddFlexibleSpace();

            scrollBarHeight = horzScrollBar.Bounds.height;
            scrollBarWidth  = vertScrollBar.Bounds.width;

            Vector2I curveEditorSize = GetCurveEditorSize();

            guiCurveEditor = new GUICurveEditor(this, editorPanel, curveEditorSize.x, curveEditorSize.y);
            guiCurveEditor.OnFrameSelected += OnFrameSelected;
            guiCurveEditor.OnEventAdded    += OnEventsChanged;
            guiCurveEditor.OnEventModified += EditorApplication.SetProjectDirty;
            guiCurveEditor.OnEventDeleted  += OnEventsChanged;
            guiCurveEditor.OnCurveModified += EditorApplication.SetProjectDirty;
            guiCurveEditor.Redraw();

            horzScrollBar.SetWidth(curveEditorSize.x);
            vertScrollBar.SetHeight(curveEditorSize.y);

            UpdateScrollBarSize();
        }