173 lines
6.4 KiB
C++
173 lines
6.4 KiB
C++
#include "CDeleteSelectionCommand.h"
|
|
#include "Editor/CSelectionIterator.h"
|
|
#include <Common/FileIO.h>
|
|
#include <Core/Resource/Cooker/CScriptCooker.h>
|
|
#include <Core/Resource/Factory/CScriptLoader.h>
|
|
|
|
CDeleteSelectionCommand::CDeleteSelectionCommand(CWorldEditor *pEditor, const QString& rkCommandName /*= "Delete"*/)
|
|
: IUndoCommand(rkCommandName)
|
|
, mpEditor(pEditor)
|
|
{
|
|
QSet<CLink*> Links;
|
|
QList<CScriptObject*> LinkedInstances;
|
|
|
|
for (CSelectionIterator It(pEditor->Selection()); It; ++It)
|
|
{
|
|
mOldSelection << *It;
|
|
|
|
if (It->NodeType() == ENodeType::Script)
|
|
{
|
|
CScriptNode *pScript = static_cast<CScriptNode*>(*It);
|
|
CScriptObject *pInst = pScript->Instance();
|
|
|
|
mDeletedNodes.push_back(SDeletedNode());
|
|
SDeletedNode& rNode = mDeletedNodes.back();
|
|
|
|
rNode.NodePtr = CNodePtr(pScript);
|
|
rNode.NodeID = pScript->ID();
|
|
rNode.Position = pScript->LocalPosition();
|
|
rNode.Rotation = pScript->LocalRotation();
|
|
rNode.Scale = pScript->LocalScale();
|
|
|
|
rNode.pArea = pInst->Area();
|
|
rNode.pLayer = pInst->Layer();
|
|
rNode.LayerIndex = pInst->LayerIndex();
|
|
|
|
for (uint32 iType = 0; iType < 2; iType++)
|
|
{
|
|
ELinkType Type = (iType == 0 ? ELinkType::Outgoing : ELinkType::Incoming);
|
|
|
|
for (uint32 iLink = 0; iLink < pInst->NumLinks(Type); iLink++)
|
|
{
|
|
CLink *pLink = pInst->Link(Type, iLink);
|
|
|
|
if (!Links.contains(pLink))
|
|
{
|
|
SDeletedLink Link;
|
|
Link.State = pLink->State();
|
|
Link.Message = pLink->Message();
|
|
Link.SenderID = pLink->SenderID();
|
|
Link.SenderIndex = pLink->SenderIndex();
|
|
Link.ReceiverID = pLink->ReceiverID();
|
|
Link.ReceiverIndex = pLink->ReceiverIndex();
|
|
Link.pSender = pLink->Sender();
|
|
Link.pReceiver = pLink->Receiver();
|
|
mDeletedLinks << Link;
|
|
Links << pLink;
|
|
|
|
if (!LinkedInstances.contains(pLink->Sender()))
|
|
LinkedInstances << pLink->Sender();
|
|
if (!LinkedInstances.contains(pLink->Receiver()))
|
|
LinkedInstances << pLink->Receiver();
|
|
}
|
|
}
|
|
}
|
|
|
|
CVectorOutStream PropertyDataOut(&rNode.InstanceData, EEndian::BigEndian);
|
|
CScriptCooker Cooker(pEditor->CurrentGame());
|
|
Cooker.WriteInstance(PropertyDataOut, pInst);
|
|
}
|
|
|
|
else
|
|
mNewSelection << *It;
|
|
}
|
|
|
|
// Remove selected objects from the linked instances list.
|
|
LinkedInstances.removeAll(nullptr);
|
|
|
|
foreach (CScriptObject *pInst, LinkedInstances)
|
|
{
|
|
if (mpEditor->Scene()->NodeForInstance(pInst)->IsSelected())
|
|
LinkedInstances.removeOne(pInst);
|
|
}
|
|
|
|
mLinkedInstances = LinkedInstances;
|
|
}
|
|
|
|
void CDeleteSelectionCommand::undo()
|
|
{
|
|
QList<CSceneNode*> NewNodes;
|
|
QList<uint32> NewInstanceIDs;
|
|
|
|
// Spawn nodes
|
|
for (int iNode = 0; iNode < mDeletedNodes.size(); iNode++)
|
|
{
|
|
SDeletedNode& rNode = mDeletedNodes[iNode];
|
|
mpEditor->NotifyNodeAboutToBeSpawned();
|
|
|
|
CMemoryInStream Mem(rNode.InstanceData.data(), rNode.InstanceData.size(), EEndian::BigEndian);
|
|
CScriptObject *pInstance = CScriptLoader::LoadInstance(Mem, rNode.pArea, rNode.pLayer, rNode.pArea->Game(), true);
|
|
CScriptNode *pNode = mpEditor->Scene()->CreateScriptNode(pInstance, rNode.NodeID);
|
|
rNode.pArea->AddInstanceToArea(pInstance);
|
|
rNode.pLayer->AddInstance(pInstance, rNode.LayerIndex);
|
|
|
|
pNode->SetPosition(rNode.Position);
|
|
pNode->SetRotation(rNode.Rotation);
|
|
pNode->SetScale(rNode.Scale);
|
|
|
|
NewNodes << pNode;
|
|
NewInstanceIDs << pInstance->InstanceID();
|
|
mpEditor->NotifyNodeSpawned(*rNode.NodePtr);
|
|
}
|
|
|
|
// Sort links by sender index, add outgoing
|
|
std::sort(mDeletedLinks.begin(), mDeletedLinks.end(), [](SDeletedLink& rLeft, SDeletedLink& rRight) -> bool {
|
|
return (rLeft.SenderIndex < rRight.SenderIndex);
|
|
});
|
|
|
|
for (int iLink = 0; iLink < mDeletedLinks.size(); iLink++)
|
|
{
|
|
SDeletedLink& rLink = mDeletedLinks[iLink];
|
|
|
|
// Adding to the sender is only needed if the sender is not one of the nodes we just spawned. If it is, it already has this link.
|
|
if (!NewInstanceIDs.contains(rLink.SenderID) && *rLink.pSender)
|
|
{
|
|
CLink *pLink = new CLink(rLink.pSender->Area(), rLink.State, rLink.Message, rLink.SenderID, rLink.ReceiverID);
|
|
rLink.pSender->AddLink(ELinkType::Outgoing, pLink, rLink.SenderIndex);
|
|
}
|
|
}
|
|
|
|
// Sort links by receiver index, add incoming
|
|
std::sort(mDeletedLinks.begin(), mDeletedLinks.end(), [](SDeletedLink& rLeft, SDeletedLink& rRight) -> bool {
|
|
return (rLeft.ReceiverIndex < rRight.ReceiverIndex);
|
|
});
|
|
|
|
for (int iLink = 0; iLink < mDeletedLinks.size(); iLink++)
|
|
{
|
|
SDeletedLink& rLink = mDeletedLinks[iLink];
|
|
|
|
if (*rLink.pReceiver)
|
|
{
|
|
CLink *pLink = (*rLink.pSender ? rLink.pSender->Link(ELinkType::Outgoing, rLink.SenderIndex) : new CLink(rLink.pReceiver->Area(), rLink.State, rLink.Message, rLink.SenderID, rLink.ReceiverID));
|
|
rLink.pReceiver->AddLink(ELinkType::Incoming, pLink, rLink.ReceiverIndex);
|
|
}
|
|
}
|
|
|
|
// Run OnLoadFinished
|
|
foreach (CSceneNode *pNode, NewNodes)
|
|
pNode->OnLoadFinished();
|
|
|
|
// Add selection and done
|
|
mpEditor->Selection()->SetSelectedNodes(mOldSelection.DereferenceList());
|
|
mpEditor->OnLinksModified(mLinkedInstances.DereferenceList());
|
|
}
|
|
|
|
void CDeleteSelectionCommand::redo()
|
|
{
|
|
mpEditor->Selection()->SetSelectedNodes(mNewSelection.DereferenceList());
|
|
|
|
for (int iNode = 0; iNode < mDeletedNodes.size(); iNode++)
|
|
{
|
|
SDeletedNode& rNode = mDeletedNodes[iNode];
|
|
CSceneNode *pNode = *rNode.NodePtr;
|
|
CScriptObject *pInst = static_cast<CScriptNode*>(pNode)->Instance();
|
|
|
|
mpEditor->NotifyNodeAboutToBeDeleted(pNode);
|
|
mpEditor->Scene()->DeleteNode(pNode);
|
|
mpEditor->ActiveArea()->DeleteInstance(pInst);
|
|
mpEditor->NotifyNodeDeleted();
|
|
}
|
|
|
|
mpEditor->OnLinksModified(mLinkedInstances.DereferenceList());
|
|
}
|