/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include "stdafx.h" #include "UiAnimViewUndo.h" #include "UiAnimViewSequenceManager.h" #include "UiAnimViewSequence.h" #include "UiAnimViewTrack.h" #include "UiAnimViewEventNode.h" #include "AnimationContext.h" #include "UiEditorAnimationBus.h" ////////////////////////////////////////////////////////////////////////// CUndoSequenceSettings::CUndoSequenceSettings(CUiAnimViewSequence* pSequence) : m_pSequence(pSequence) , m_oldTimeRange(pSequence->GetTimeRange()) , m_oldFlags(pSequence->GetFlags()) { } ////////////////////////////////////////////////////////////////////////// void CUndoSequenceSettings::Undo(bool bUndo) { m_newTimeRange = m_pSequence->GetTimeRange(); m_newFlags = m_pSequence->GetFlags(); m_pSequence->SetTimeRange(m_oldTimeRange); m_pSequence->SetFlags(m_oldFlags); } ////////////////////////////////////////////////////////////////////////// void CUndoSequenceSettings::Redo() { m_pSequence->SetTimeRange(m_newTimeRange); m_pSequence->SetFlags(m_newFlags); } ////////////////////////////////////////////////////////////////////////// CUndoAnimKeySelection::CUndoAnimKeySelection(CUiAnimViewSequence* pSequence) : m_pSequence(pSequence) { // Stores the current state of this sequence. assert(pSequence); // Save sequence name and key selection states m_undoKeyStates = SaveKeyStates(pSequence); } ////////////////////////////////////////////////////////////////////////// CUndoAnimKeySelection::CUndoAnimKeySelection(CUiAnimViewTrack* pTrack) : m_pSequence(pTrack->GetSequence()) { // This is called from CUndoTrackObject which will save key states itself } ////////////////////////////////////////////////////////////////////////// void CUndoAnimKeySelection::Undo(bool bUndo) { { CUiAnimViewSequenceNoNotificationContext context(m_pSequence); // Save key selection states for redo if necessary if (bUndo) { m_redoKeyStates = SaveKeyStates(m_pSequence); } // Undo key selection state RestoreKeyStates(m_pSequence, m_undoKeyStates); } if (bUndo) { m_pSequence->OnKeySelectionChanged(); } } ////////////////////////////////////////////////////////////////////////// void CUndoAnimKeySelection::Redo() { // Redo key selection state RestoreKeyStates(m_pSequence, m_redoKeyStates); } ////////////////////////////////////////////////////////////////////////// std::vector<bool> CUndoAnimKeySelection::SaveKeyStates(CUiAnimViewSequence* pSequence) const { CUiAnimViewKeyBundle keys = pSequence->GetAllKeys(); const unsigned int numkeys = keys.GetKeyCount(); std::vector<bool> selectionState; selectionState.reserve(numkeys); for (unsigned int i = 0; i < numkeys; ++i) { CUiAnimViewKeyHandle keyHandle = keys.GetKey(i); selectionState.push_back(keyHandle.IsSelected()); } return selectionState; } ////////////////////////////////////////////////////////////////////////// void CUndoAnimKeySelection::RestoreKeyStates(CUiAnimViewSequence* pSequence, const std::vector<bool> keyStates) { CUiAnimViewKeyBundle keys = pSequence->GetAllKeys(); const unsigned int numkeys = keys.GetKeyCount(); assert(numkeys <= keyStates.size()); CUiAnimViewSequenceNotificationContext context(pSequence); for (unsigned int i = 0; i < numkeys; ++i) { CUiAnimViewKeyHandle keyHandle = keys.GetKey(i); keyHandle.Select(keyStates[i]); } } ////////////////////////////////////////////////////////////////////////// bool CUndoAnimKeySelection::IsSelectionChanged() const { const std::vector<bool> currentKeyState = SaveKeyStates(m_pSequence); return m_undoKeyStates != currentKeyState; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// CUndoTrackObject::CUndoTrackObject(CUiAnimViewTrack* pTrack, bool bStoreKeySelection) : CUndoAnimKeySelection(pTrack) , m_pTrack(pTrack) , m_bStoreKeySelection(bStoreKeySelection) { assert(pTrack); if (m_bStoreKeySelection) { m_undoKeyStates = SaveKeyStates(m_pSequence); } // Stores the current state of this track. assert(pTrack != 0); // Store undo info. m_undo = pTrack->GetMemento(); } ////////////////////////////////////////////////////////////////////////// void CUndoTrackObject::Undo(bool bUndo) { assert(m_pSequence); { CUiAnimViewSequenceNoNotificationContext context(m_pSequence); if (bUndo) { m_redo = m_pTrack->GetMemento(); if (m_bStoreKeySelection) { // Save key selection states for redo if necessary m_redoKeyStates = SaveKeyStates(m_pSequence); } } // Undo track state. m_pTrack->RestoreFromMemento(m_undo); if (m_bStoreKeySelection) { // Undo key selection state RestoreKeyStates(m_pSequence, m_undoKeyStates); } } if (bUndo) { m_pSequence->OnKeysChanged(); } else { m_pSequence->ForceAnimation(); } } ////////////////////////////////////////////////////////////////////////// void CUndoTrackObject::Redo() { assert(m_pSequence); // Redo track state. m_pTrack->RestoreFromMemento(m_redo); if (m_bStoreKeySelection) { // Redo key selection state RestoreKeyStates(m_pSequence, m_redoKeyStates); } m_pSequence->OnKeysChanged(); } ////////////////////////////////////////////////////////////////////////// CAbstractUndoSequenceTransaction::CAbstractUndoSequenceTransaction(CUiAnimViewSequence* pSequence) : m_pSequence(pSequence) { } ////////////////////////////////////////////////////////////////////////// void CAbstractUndoSequenceTransaction::AddSequence() { CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager(); IUiAnimationSystem* pUiAnimationSystem = nullptr; EBUS_EVENT_RESULT(pUiAnimationSystem, UiEditorAnimationBus, GetAnimationSystem); // Add sequence back to UI Animation system pUiAnimationSystem->AddSequence(m_pSequence->m_pAnimSequence.get()); // Release ownership and add node back to UI Animation system CUiAnimViewSequence* pSequence = m_pStoredUiAnimViewSequence.release(); pSequenceManager->m_sequences.push_back(std::unique_ptr<CUiAnimViewSequence>(m_pSequence)); pSequenceManager->OnSequenceAdded(m_pSequence); } ////////////////////////////////////////////////////////////////////////// void CAbstractUndoSequenceTransaction::RemoveSequence(bool bAquireOwnership) { CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager(); for (auto iter = pSequenceManager->m_sequences.begin(); iter != pSequenceManager->m_sequences.end(); ++iter) { std::unique_ptr<CUiAnimViewSequence>& currentSequence = *iter; if (currentSequence.get() == m_pSequence) { if (bAquireOwnership) { // Acquire ownership of sequence currentSequence.swap(m_pStoredUiAnimViewSequence); assert(m_pStoredUiAnimViewSequence.get()); } // Remove from UI Animation system and UiAnimView pSequenceManager->m_sequences.erase(iter); IUiAnimationSystem* pUiAnimationSystem = nullptr; EBUS_EVENT_RESULT(pUiAnimationSystem, UiEditorAnimationBus, GetAnimationSystem); pUiAnimationSystem->RemoveSequence(m_pSequence->m_pAnimSequence.get()); break; } } pSequenceManager->OnSequenceRemoved(m_pSequence); } ////////////////////////////////////////////////////////////////////////// void CUndoSequenceAdd::Undo(bool bUndo) { RemoveSequence(bUndo); } ////////////////////////////////////////////////////////////////////////// void CUndoSequenceAdd::Redo() { AddSequence(); } ////////////////////////////////////////////////////////////////////////// CUndoSequenceRemove::CUndoSequenceRemove(CUiAnimViewSequence* pRemovedSequence) : CAbstractUndoSequenceTransaction(pRemovedSequence) { RemoveSequence(true); } ////////////////////////////////////////////////////////////////////////// void CUndoSequenceRemove::Undo(bool bUndo) { AddSequence(); } ////////////////////////////////////////////////////////////////////////// void CUndoSequenceRemove::Redo() { RemoveSequence(true); } ////////////////////////////////////////////////////////////////////////// CUndoSequenceChange::CUndoSequenceChange(CUiAnimViewSequence* oldSequence, CUiAnimViewSequence* newSequence) : m_oldSequence(oldSequence) , m_newSequence(newSequence) { } ////////////////////////////////////////////////////////////////////////// void CUndoSequenceChange::ChangeSequence(CUiAnimViewSequence* sequence) { CUiAnimationContext* animContext = nullptr; UiEditorAnimationBus::BroadcastResult(animContext, &UiEditorAnimationBus::Events::GetAnimationContext); if (animContext) { animContext->SetSequence(sequence, false, false); } else { AZ_Assert(false, "Active UI animation sequence failed to be changed."); } } ////////////////////////////////////////////////////////////////////////// void CUndoSequenceChange::Undo(bool undo) { AZ_UNUSED(undo); ChangeSequence(m_oldSequence); } ////////////////////////////////////////////////////////////////////////// void CUndoSequenceChange::Redo() { ChangeSequence(m_newSequence); } ////////////////////////////////////////////////////////////////////////// CAbstractUndoAnimNodeTransaction::CAbstractUndoAnimNodeTransaction(CUiAnimViewAnimNode* pNode) : m_pParentNode(static_cast<CUiAnimViewAnimNode*>(pNode->GetParentNode())) , m_pNode(pNode) { } ////////////////////////////////////////////////////////////////////////// void CAbstractUndoAnimNodeTransaction::AddNode() { // Add node back to sequence m_pParentNode->m_pAnimSequence->AddNode(m_pNode->m_pAnimNode.get()); // Release ownership and add node back to parent node CUiAnimViewNode* pNode = m_pStoredUiAnimViewNode.release(); m_pParentNode->AddNode(m_pNode); m_pNode->BindToEditorObjects(); } ////////////////////////////////////////////////////////////////////////// void CAbstractUndoAnimNodeTransaction::RemoveNode(bool bAquireOwnership) { m_pNode->UnBindFromEditorObjects(); for (auto iter = m_pParentNode->m_childNodes.begin(); iter != m_pParentNode->m_childNodes.end(); ++iter) { std::unique_ptr<CUiAnimViewNode>& currentNode = *iter; if (currentNode.get() == m_pNode) { if (bAquireOwnership) { // Acquire ownership of node currentNode.swap(m_pStoredUiAnimViewNode); assert(m_pStoredUiAnimViewNode.get()); } // Remove from parent node and sequence m_pParentNode->m_childNodes.erase(iter); m_pParentNode->m_pAnimSequence->RemoveNode(m_pNode->m_pAnimNode.get()); break; } } m_pNode->GetSequence()->OnNodeChanged(m_pNode, IUiAnimViewSequenceListener::eNodeChangeType_Removed); } ////////////////////////////////////////////////////////////////////////// void CUndoAnimNodeAdd::Undo(bool bUndo) { RemoveNode(bUndo); } ////////////////////////////////////////////////////////////////////////// void CUndoAnimNodeAdd::Redo() { AddNode(); } ////////////////////////////////////////////////////////////////////////// CUndoAnimNodeRemove::CUndoAnimNodeRemove(CUiAnimViewAnimNode* pRemovedNode) : CAbstractUndoAnimNodeTransaction(pRemovedNode) { RemoveNode(true); } ////////////////////////////////////////////////////////////////////////// void CUndoAnimNodeRemove::Undo(bool bUndo) { AddNode(); } ////////////////////////////////////////////////////////////////////////// void CUndoAnimNodeRemove::Redo() { RemoveNode(true); } ////////////////////////////////////////////////////////////////////////// CAbstractUndoTrackTransaction::CAbstractUndoTrackTransaction(CUiAnimViewTrack* pTrack) : m_pParentNode(pTrack->GetAnimNode()) , m_pTrack(pTrack) { assert(!pTrack->IsSubTrack()); } ////////////////////////////////////////////////////////////////////////// void CAbstractUndoTrackTransaction::AddTrack() { // Add node back to sequence m_pParentNode->m_pAnimNode->AddTrack(m_pTrack->m_pAnimTrack.get()); // Add track back to parent node and release ownership CUiAnimViewNode* pTrack = m_pStoredUiAnimViewTrack.release(); m_pParentNode->AddNode(pTrack); } ////////////////////////////////////////////////////////////////////////// void CAbstractUndoTrackTransaction::RemoveTrack(bool bAquireOwnership) { for (auto iter = m_pParentNode->m_childNodes.begin(); iter != m_pParentNode->m_childNodes.end(); ++iter) { std::unique_ptr<CUiAnimViewNode>& currentNode = *iter; if (currentNode.get() == m_pTrack) { if (bAquireOwnership) { // Acquire ownership of track currentNode.swap(m_pStoredUiAnimViewTrack); } // Remove from parent node and sequence m_pParentNode->m_childNodes.erase(iter); m_pParentNode->m_pAnimNode->RemoveTrack(m_pTrack->m_pAnimTrack.get()); break; } } m_pParentNode->GetSequence()->OnNodeChanged(m_pStoredUiAnimViewTrack.get(), IUiAnimViewSequenceListener::eNodeChangeType_Removed); } ////////////////////////////////////////////////////////////////////////// void CUndoTrackAdd::Undo(bool bUndo) { RemoveTrack(bUndo); } ////////////////////////////////////////////////////////////////////////// void CUndoTrackAdd::Redo() { AddTrack(); } ////////////////////////////////////////////////////////////////////////// CUndoTrackRemove::CUndoTrackRemove(CUiAnimViewTrack* pRemovedTrack) : CAbstractUndoTrackTransaction(pRemovedTrack) { RemoveTrack(true); } ////////////////////////////////////////////////////////////////////////// void CUndoTrackRemove::Undo(bool bUndo) { AddTrack(); } ////////////////////////////////////////////////////////////////////////// void CUndoTrackRemove::Redo() { RemoveTrack(true); } ////////////////////////////////////////////////////////////////////////// CUndoAnimNodeReparent::CUndoAnimNodeReparent(CUiAnimViewAnimNode* pAnimNode, CUiAnimViewAnimNode* pNewParent) : CAbstractUndoAnimNodeTransaction(pAnimNode) , m_pNewParent(pNewParent) , m_pOldParent(m_pParentNode) { CUiAnimViewSequence* pSequence = pAnimNode->GetSequence(); assert(pSequence == m_pNewParent->GetSequence() && pSequence == m_pOldParent->GetSequence()); Reparent(pNewParent); } ////////////////////////////////////////////////////////////////////////// void CUndoAnimNodeReparent::Undo(bool bUndo) { Reparent(m_pOldParent); } ////////////////////////////////////////////////////////////////////////// void CUndoAnimNodeReparent::Redo() { Reparent(m_pNewParent); } ////////////////////////////////////////////////////////////////////////// void CUndoAnimNodeReparent::Reparent(CUiAnimViewAnimNode* pNewParent) { RemoveNode(true); m_pParentNode = pNewParent; m_pNode->m_pAnimNode->SetParent(pNewParent->m_pAnimNode.get()); AddParentsInChildren(m_pNode); AddNode(); // This undo object must never have ownership of the node assert(m_pStoredUiAnimViewNode.get() == nullptr); } void CUndoAnimNodeReparent::AddParentsInChildren(CUiAnimViewAnimNode* pCurrentNode) { const uint numChildren = pCurrentNode->GetChildCount(); for (uint childIndex = 0; childIndex < numChildren; ++childIndex) { CUiAnimViewAnimNode* pChildAnimNode = static_cast<CUiAnimViewAnimNode*>(pCurrentNode->GetChild(childIndex)); if (pChildAnimNode->GetNodeType() != eUiAVNT_Track) { pChildAnimNode->m_pAnimNode->SetParent(pCurrentNode->m_pAnimNode.get()); if (pChildAnimNode->GetChildCount() > 0 && pChildAnimNode->GetNodeType() != eUiAVNT_AnimNode) { AddParentsInChildren(pChildAnimNode); } } } } ////////////////////////////////////////////////////////////////////////// CUndoAnimNodeRename::CUndoAnimNodeRename(CUiAnimViewAnimNode* pNode, const string& oldName) : m_pNode(pNode) , m_newName(pNode->GetName()) , m_oldName(oldName) { } ////////////////////////////////////////////////////////////////////////// void CUndoAnimNodeRename::Undo(bool bUndo) { m_pNode->SetName(m_oldName); } ////////////////////////////////////////////////////////////////////////// void CUndoAnimNodeRename::Redo() { m_pNode->SetName(m_newName); } ////////////////////////////////////////////////////////////////////////// CAbstractUndoTrackEventTransaction::CAbstractUndoTrackEventTransaction(CUiAnimViewSequence* pSequence, const QString& eventName) : m_pSequence(pSequence) , m_eventName(eventName) { } ////////////////////////////////////////////////////////////////////////// void CUndoTrackEventAdd::Undo(bool bUndo) { AZ_UNUSED(bUndo); m_pSequence->RemoveTrackEvent(m_eventName.toUtf8().data()); } ////////////////////////////////////////////////////////////////////////// void CUndoTrackEventAdd::Redo() { m_pSequence->AddTrackEvent(m_eventName.toUtf8().data()); } ////////////////////////////////////////////////////////////////////////// CUndoTrackEventRemove::CUndoTrackEventRemove(CUiAnimViewSequence* pSequence, const QString& eventName) : CAbstractUndoTrackEventTransaction(pSequence, eventName) , m_changedKeys(CUiAnimViewEventNode::GetTrackEventKeys(pSequence, eventName.toUtf8().data())) { } ////////////////////////////////////////////////////////////////////////// void CUndoTrackEventRemove::Undo(bool bUndo) { AZ_UNUSED(bUndo); const char* rawName = m_eventName.toUtf8().data(); m_pSequence->AddTrackEvent(rawName); const uint numKeys = m_changedKeys.GetKeyCount(); for (uint keyIndex = 0; keyIndex < numKeys; ++keyIndex) { CUiAnimViewKeyHandle keyHandle = m_changedKeys.GetKey(keyIndex); IEventKey eventKey; keyHandle.GetKey(&eventKey); // re-set the eventKey with the m_eventName eventKey.event = rawName; keyHandle.SetKey(&eventKey); } } ////////////////////////////////////////////////////////////////////////// void CUndoTrackEventRemove::Redo() { m_pSequence->RemoveTrackEvent(m_eventName.toUtf8().data()); } ////////////////////////////////////////////////////////////////////////// CUndoTrackEventRename::CUndoTrackEventRename(CUiAnimViewSequence* pSequence, const QString& eventName, const QString& newEventName) : CAbstractUndoTrackEventTransaction(pSequence, eventName) , m_newEventName(newEventName) { } ////////////////////////////////////////////////////////////////////////// void CUndoTrackEventRename::Undo(bool bUndo) { AZ_UNUSED(bUndo); m_pSequence->RenameTrackEvent(m_newEventName.toUtf8().data(), m_eventName.toUtf8().data()); } ////////////////////////////////////////////////////////////////////////// void CUndoTrackEventRename::Redo() { m_pSequence->RenameTrackEvent(m_eventName.toUtf8().data(), m_newEventName.toUtf8().data()); } ////////////////////////////////////////////////////////////////////////// void CAbstractUndoTrackEventMove::MoveUp() { m_pSequence->MoveUpTrackEvent(m_eventName.toUtf8().data()); } ////////////////////////////////////////////////////////////////////////// void CAbstractUndoTrackEventMove::MoveDown() { m_pSequence->MoveDownTrackEvent(m_eventName.toUtf8().data()); } ////////////////////////////////////////////////////////////////////////// void CUndoTrackEventMoveUp::Undo(bool bUndo) { AZ_UNUSED(bUndo); MoveDown(); } ////////////////////////////////////////////////////////////////////////// void CUndoTrackEventMoveUp::Redo() { MoveUp(); } ////////////////////////////////////////////////////////////////////////// void CUndoTrackEventMoveDown::Undo(bool bUndo) { AZ_UNUSED(bUndo); MoveUp(); } ////////////////////////////////////////////////////////////////////////// void CUndoTrackEventMoveDown::Redo() { MoveDown(); }