Implemented functionality for editing, creating, and deleting script object links

This commit is contained in:
parax0 2016-03-06 17:44:51 -07:00
parent 984d9cf3f3
commit 8f82dcbdd9
33 changed files with 805 additions and 219 deletions

View File

@ -186,7 +186,7 @@ HEADERS += \
Resource/Factory/CSectionMgrIn.h \
Resource/Cooker/CScriptCooker.h \
ScriptExtra/CSplinePathExtra.h \
Resource/Script/SLink.h
Resource/Script/CLink.h
# Source Files
SOURCES += \

View File

@ -1,4 +1,5 @@
#include "CScriptCooker.h"
#include "Core/Resource/Script/CLink.h"
void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
{
@ -211,14 +212,14 @@ void CScriptCooker::WriteInstanceMP1(CScriptObject *pInstance)
u32 InstanceStart = mpSCLY->Tell();
mpSCLY->WriteLong(pInstance->InstanceID());
mpSCLY->WriteLong(pInstance->NumOutLinks());
mpSCLY->WriteLong(pInstance->NumLinks(eOutgoing));
for (u32 iLink = 0; iLink < pInstance->NumOutLinks(); iLink++)
for (u32 iLink = 0; iLink < pInstance->NumLinks(eOutgoing); iLink++)
{
const SLink& rkLink = pInstance->OutLink(iLink);
mpSCLY->WriteLong(rkLink.State);
mpSCLY->WriteLong(rkLink.Message);
mpSCLY->WriteLong(rkLink.ObjectID);
CLink *pLink = pInstance->Link(eOutgoing, iLink);
mpSCLY->WriteLong(pLink->State());
mpSCLY->WriteLong(pLink->Message());
mpSCLY->WriteLong(pLink->ReceiverID());
}
WriteProperty(pInstance->Properties(), false);
@ -261,14 +262,14 @@ void CScriptCooker::WriteInstanceMP2(CScriptObject *pInstance)
u32 InstanceStart = mpSCLY->Tell();
mpSCLY->WriteLong(pInstance->InstanceID());
mpSCLY->WriteShort((u16) pInstance->NumOutLinks());
mpSCLY->WriteShort((u16) pInstance->NumLinks(eOutgoing));
for (u32 iLink = 0; iLink < pInstance->NumOutLinks(); iLink++)
for (u32 iLink = 0; iLink < pInstance->NumLinks(eOutgoing); iLink++)
{
const SLink& rkLink = pInstance->OutLink(iLink);
mpSCLY->WriteLong(rkLink.State);
mpSCLY->WriteLong(rkLink.Message);
mpSCLY->WriteLong(rkLink.ObjectID);
CLink *pLink = pInstance->Link(eOutgoing, iLink);
mpSCLY->WriteLong(pLink->State());
mpSCLY->WriteLong(pLink->Message());
mpSCLY->WriteLong(pLink->ReceiverID());
}
WriteProperty(pInstance->Properties(), false);

View File

@ -627,15 +627,10 @@ void CAreaLoader::SetUpObjects()
mpArea->mObjectMap[pObj->InstanceID()] = pObj;
// Store outgoing connections
for (u32 iCon = 0; iCon < pObj->NumOutLinks(); iCon++)
for (u32 iCon = 0; iCon < pObj->NumLinks(eOutgoing); iCon++)
{
SLink Connection = pObj->OutLink(iCon);
SLink NewConnection;
NewConnection.State = Connection.State;
NewConnection.Message = Connection.Message;
NewConnection.ObjectID = pObj->InstanceID();
mConnectionMap[Connection.ObjectID].push_back(NewConnection);
CLink *pLink = pObj->Link(eOutgoing, iCon);
mConnectionMap[pLink->ReceiverID()].push_back(pLink);
}
}
}
@ -649,7 +644,7 @@ void CAreaLoader::SetUpObjects()
if (iConMap != mConnectionMap.end())
{
CScriptObject *pObj = mpArea->GetInstanceByID(InstanceID);
pObj->mInConnections = iConMap->second;
pObj->mInLinks = iConMap->second;
}
}
}

View File

@ -2,7 +2,7 @@
#define CAREALOADER_H
#include "CSectionMgrIn.h"
#include "Core/Resource/Script/SLink.h"
#include "Core/Resource/Script/CLink.h"
#include "Core/Resource/CGameArea.h"
#include "Core/Resource/EGame.h"
#include "Core/Resource/CResCache.h"
@ -22,7 +22,7 @@ class CAreaLoader
u32 mNumLayers;
// Object connections
std::unordered_map<u32, std::vector<SLink>> mConnectionMap;
std::unordered_map<u32, std::vector<CLink*>> mConnectionMap;
// Compression
u8 *mDecmpBuffer;

View File

@ -219,15 +219,16 @@ CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& SCLY)
// Load connections
u32 NumLinks = SCLY.ReadLong();
mpObj->mOutConnections.reserve(NumLinks);
mpObj->mOutLinks.reserve(NumLinks);
for (u32 iLink = 0; iLink < NumLinks; iLink++)
{
SLink Link;
Link.State = SCLY.ReadLong();
Link.Message = SCLY.ReadLong();
Link.ObjectID = SCLY.ReadLong();
mpObj->mOutConnections.push_back(Link);
u32 State = SCLY.ReadLong();
u32 Message = SCLY.ReadLong();
u32 ReceiverID = SCLY.ReadLong();
CLink *pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID);
mpObj->mOutLinks.push_back(pLink);
}
// Load object...
@ -331,15 +332,16 @@ CScriptObject* CScriptLoader::LoadObjectMP2(IInputStream& SCLY)
// Load connections
u32 NumConnections = SCLY.ReadShort();
mpObj->mOutConnections.reserve(NumConnections);
mpObj->mOutLinks.reserve(NumConnections);
for (u32 iCon = 0; iCon < NumConnections; iCon++)
{
SLink Link;
Link.State = SCLY.ReadLong();
Link.Message = SCLY.ReadLong();
Link.ObjectID = SCLY.ReadLong();
mpObj->mOutConnections.push_back(Link);
u32 State = SCLY.ReadLong();
u32 Message = SCLY.ReadLong();
u32 ReceiverID = SCLY.ReadLong();
CLink *pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID);
mpObj->mOutLinks.push_back(pLink);
}
// Load object

View File

@ -0,0 +1,128 @@
#ifndef CLINK_H
#define CLINK_H
#include "CScriptObject.h"
#include "Core/Resource/CGameArea.h"
#include <Common/TString.h>
#include <Common/types.h>
struct SState
{
u32 ID;
TString Name;
SState() {}
SState(u32 _ID, const TString& rkName) : ID(_ID), Name(rkName) {}
};
struct SMessage
{
u32 ID;
TString Name;
SMessage() {}
SMessage(u32 _ID, const TString& rkName) : ID(_ID), Name(rkName) {}
};
class CLink
{
CGameArea *mpArea;
u32 mStateID;
u32 mMessageID;
u32 mSenderID;
u32 mReceiverID;
public:
CLink(CGameArea *pArea)
: mpArea(pArea)
, mStateID(-1)
, mMessageID(-1)
, mSenderID(-1)
, mReceiverID(-1)
{}
CLink(CGameArea *pArea, u32 StateID, u32 MessageID, u32 SenderID, u32 ReceiverID)
: mpArea(pArea)
, mStateID(StateID)
, mMessageID(MessageID)
, mSenderID(SenderID)
, mReceiverID(ReceiverID)
{}
void SetSender(u32 NewSenderID, u32 Index = -1)
{
u32 OldSenderID = mSenderID;
CScriptObject *pOldSender = mpArea->GetInstanceByID(OldSenderID);
CScriptObject *pNewSender = mpArea->GetInstanceByID(NewSenderID);
mSenderID = NewSenderID;
pOldSender->RemoveLink(eOutgoing, this);
pNewSender->AddLink(eOutgoing, this, Index);
}
void SetReceiver(u32 NewReceiverID, u32 Index = -1)
{
u32 OldReceiverID = mSenderID;
CScriptObject *pOldReceiver = mpArea->GetInstanceByID(OldReceiverID);
CScriptObject *pNewReceiver = mpArea->GetInstanceByID(NewReceiverID);
mReceiverID = NewReceiverID;
pOldReceiver->RemoveLink(eIncoming, this);
pNewReceiver->AddLink(eIncoming, this, Index);
}
u32 SenderIndex() const
{
CScriptObject *pSender = mpArea->GetInstanceByID(mSenderID);
for (u32 iLink = 0; iLink < pSender->NumLinks(eOutgoing); iLink++)
{
if (pSender->Link(eOutgoing, iLink) == this)
return iLink;
}
return -1;
}
u32 ReceiverIndex() const
{
CScriptObject *pReceiver = mpArea->GetInstanceByID(mReceiverID);
for (u32 iLink = 0; iLink < pReceiver->NumLinks(eIncoming); iLink++)
{
if (pReceiver->Link(eIncoming, iLink) == this)
return iLink;
}
return -1;
}
// Operators
bool operator==(const CLink& rkOther)
{
return ( (mpArea == rkOther.mpArea) &&
(mStateID == rkOther.mStateID) &&
(mMessageID == rkOther.mMessageID) &&
(mSenderID == rkOther.mSenderID) &&
(mReceiverID == rkOther.mReceiverID) );
}
bool operator!=(const CLink& rkOther)
{
return (!(*this == rkOther));
}
// Accessors
u32 State() const { return mStateID; }
u32 Message() const { return mMessageID; }
u32 SenderID() const { return mSenderID; }
u32 ReceiverID() const { return mReceiverID; }
CScriptObject* Sender() const { return mpArea->GetInstanceByID(mSenderID); }
CScriptObject* Receiver() const { return mpArea->GetInstanceByID(mReceiverID); }
void SetState(u32 StateID) { mStateID = StateID; }
void SetMessage(u32 MessageID) { mMessageID = MessageID; }
};
#endif // CLINK_H

View File

@ -2,7 +2,7 @@
#define CMASTERTEMPLATE_H
#include "CScriptTemplate.h"
#include "SLink.h"
#include "CLink.h"
#include "Core/Resource/EGame.h"
#include <Common/types.h>
#include <map>

View File

@ -21,6 +21,10 @@ CScriptObject::~CScriptObject()
{
if (mpProperties) delete mpProperties;
mpTemplate->RemoveObject(this);
// Note: Incoming links will be deleted by the sender.
for (u32 iLink = 0; iLink < mOutLinks.size(); iLink++)
delete mOutLinks[iLink];
}
// ************ DATA MANIPULATION ************
@ -94,17 +98,17 @@ bool CScriptObject::HasNearVisibleActivation() const
if (mIsCheckingNearVisibleActivation) return false;
mIsCheckingNearVisibleActivation = true;
for (u32 iLink = 0; iLink < mInConnections.size(); iLink++)
for (u32 iLink = 0; iLink < mInLinks.size(); iLink++)
{
const SLink& rkLink = mInConnections[iLink];
CLink *pLink = mInLinks[iLink];
// Check for trigger activation
if (rkLink.State == 0x49533034 || rkLink.State == 0x49533035 || rkLink.State == 0x49533036) // "IS04", "IS05", or "IS06"
if (pLink->State() == 0x49533034 || pLink->State() == 0x49533035 || pLink->State() == 0x49533036) // "IS04", "IS05", or "IS06"
{
if ( (!IsRelay && rkLink.Message == 0x41435456) || // "ACTV"
(IsRelay && rkLink.Message == 0x4143544E) ) // "ACTN"
if ( (!IsRelay && pLink->Message() == 0x41435456) || // "ACTV"
(IsRelay && pLink->Message() == 0x4143544E) ) // "ACTN"
{
CScriptObject *pObj = mpArea->GetInstanceByID(rkLink.ObjectID);
CScriptObject *pObj = pLink->Sender();
if (pObj->ObjectTypeID() == 0x54524752) // "TRGR"
{
@ -115,12 +119,12 @@ bool CScriptObject::HasNearVisibleActivation() const
}
// Check for relay activation
else if (rkLink.State == 0x524C4159) // "RLAY"
else if (pLink->State() == 0x524C4159) // "RLAY"
{
if ( (!IsRelay && rkLink.Message == 0x41435456) || // "ACTV"
(IsRelay && rkLink.Message == 0x4143544E) ) // "ACTN"
if ( (!IsRelay && pLink->Message() == 0x41435456) || // "ACTV"
(IsRelay && pLink->Message() == 0x4143544E) ) // "ACTN"
{
CScriptObject *pObj = mpArea->GetInstanceByID(rkLink.ObjectID);
CScriptObject *pObj = pLink->Sender();
if (pObj->ObjectTypeID() == 0x53524C59) // "SRLY"
Relays.push_back(pObj);
@ -198,24 +202,42 @@ u32 CScriptObject::InstanceID() const
return mInstanceID;
}
u32 CScriptObject::NumInLinks() const
u32 CScriptObject::NumLinks(ELinkType Type) const
{
return mInConnections.size();
return (Type == eIncoming ? mInLinks.size() : mOutLinks.size());
}
u32 CScriptObject::NumOutLinks() const
CLink* CScriptObject::Link(ELinkType Type, u32 Index) const
{
return mOutConnections.size();
return (Type == eIncoming ? mInLinks[Index] : mOutLinks[Index]);
}
const SLink& CScriptObject::InLink(u32 index) const
void CScriptObject::AddLink(ELinkType Type, CLink *pLink, u32 Index /*= -1*/)
{
return mInConnections[index];
std::vector<CLink*> *pLinkVec = (Type == eIncoming ? &mInLinks : &mOutLinks);
if (Index == -1 || Index == pLinkVec->size())
pLinkVec->push_back(pLink);
else
{
auto it = pLinkVec->begin();
std::advance(it, Index);
pLinkVec->insert(it, pLink);
}
}
const SLink& CScriptObject::OutLink(u32 index) const
void CScriptObject::RemoveLink(ELinkType Type, CLink *pLink)
{
return mOutConnections[index];
std::vector<CLink*> *pLinkVec = (Type == eIncoming ? &mInLinks : &mOutLinks);
for (auto it = pLinkVec->begin(); it != pLinkVec->end(); it++)
{
if (*it == pLink)
{
pLinkVec->erase(it);
break;
}
}
}
TString CScriptObject::InstanceName() const

View File

@ -1,7 +1,6 @@
#ifndef CSCRIPTOBJECT_H
#define CSCRIPTOBJECT_H
#include "SLink.h"
#include "IProperty.h"
#include "IPropertyTemplate.h"
#include "CScriptTemplate.h"
@ -10,6 +9,13 @@
#include "Core/Resource/CGameArea.h"
class CScriptLayer;
class CLink;
enum ELinkType
{
eIncoming,
eOutgoing
};
class CScriptObject
{
@ -22,8 +28,8 @@ class CScriptObject
u32 mVersion;
u32 mInstanceID;
std::vector<SLink> mOutConnections;
std::vector<SLink> mInConnections;
std::vector<CLink*> mOutLinks;
std::vector<CLink*> mInLinks;
CPropertyStruct *mpProperties;
TStringProperty *mpInstanceName;
@ -67,10 +73,11 @@ public:
IProperty* PropertyByIDString(const TIDString& str) const;
u32 ObjectTypeID() const;
u32 InstanceID() const;
u32 NumInLinks() const;
u32 NumOutLinks() const;
const SLink& InLink(u32 index) const;
const SLink& OutLink(u32 index) const;
u32 NumLinks(ELinkType Type) const;
CLink* Link(ELinkType Type, u32 Index) const;
void AddLink(ELinkType Type, CLink *pLink, u32 Index = -1);
void RemoveLink(ELinkType Type, CLink *pLink);
CVector3f Position() const;
CVector3f Rotation() const;

View File

@ -1,32 +0,0 @@
#ifndef SLINK_H
#define SLINK_H
#include <Common/TString.h>
#include <Common/types.h>
struct SState
{
u32 ID;
TString Name;
SState() {}
SState(u32 _ID, const TString& rkName) : ID(_ID), Name(rkName) {}
};
struct SMessage
{
u32 ID;
TString Name;
SMessage() {}
SMessage(u32 _ID, const TString& rkName) : ID(_ID), Name(rkName) {}
};
struct SLink
{
u32 State;
u32 Message;
u32 ObjectID; // not a pointer because it can refer to objects outside the current area
};
#endif // SLINK_H

View File

@ -255,18 +255,18 @@ void CScriptNode::DrawSelection()
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
CGraphics::UpdateMVPBlock();
for (u32 iIn = 0; iIn < mpInstance->NumInLinks(); iIn++)
for (u32 iIn = 0; iIn < mpInstance->NumLinks(eIncoming); iIn++)
{
// Don't draw in links if the other object is selected.
const SLink& con = mpInstance->InLink(iIn);
CScriptNode *pLinkNode = mpScene->ScriptNodeByID(con.ObjectID);
CLink *pLink = mpInstance->Link(eIncoming, iIn);
CScriptNode *pLinkNode = mpScene->ScriptNodeByID(pLink->SenderID());
if (pLinkNode && !pLinkNode->IsSelected()) CDrawUtil::DrawLine(CenterPoint(), pLinkNode->CenterPoint(), CColor::skTransparentRed);
}
for (u32 iOut = 0; iOut < mpInstance->NumOutLinks(); iOut++)
for (u32 iOut = 0; iOut < mpInstance->NumLinks(eOutgoing); iOut++)
{
const SLink& con = mpInstance->OutLink(iOut);
CScriptNode *pLinkNode = mpScene->ScriptNodeByID(con.ObjectID);
CLink *pLink = mpInstance->Link(eOutgoing, iOut);
CScriptNode *pLinkNode = mpScene->ScriptNodeByID(pLink->ReceiverID());
if (pLinkNode) CDrawUtil::DrawLine(CenterPoint(), pLinkNode->CenterPoint(), CColor::skTransparentGreen);
}
}
@ -429,6 +429,11 @@ CColor CScriptNode::TintColor(const SViewInfo &ViewInfo) const
return BaseColor;
}
void CScriptNode::LinksModified()
{
if (mpExtra) mpExtra->LinksModified();
}
void CScriptNode::PropertyModified(IProperty *pProp)
{
// Update volume
@ -534,13 +539,13 @@ void CScriptNode::GeneratePosition()
// Ideal way to generate the position is to find a spot close to where it's being used.
// To do this I check the location of the objects that this one is linked to.
u32 NumLinks = mpInstance->NumInLinks() + mpInstance->NumOutLinks();
u32 NumLinks = mpInstance->NumLinks(eIncoming) + mpInstance->NumLinks(eOutgoing);
// In the case of one link, apply an offset so the new position isn't the same place as the object it's linked to
if (NumLinks == 1)
{
const SLink& link = (mpInstance->NumInLinks() > 0 ? mpInstance->InLink(0) : mpInstance->OutLink(0));
CScriptNode *pNode = mpScene->ScriptNodeByID(link.ObjectID);
u32 LinkedID = (mpInstance->NumLinks(eIncoming) > 0 ? mpInstance->Link(eIncoming, 0)->SenderID() : mpInstance->Link(eOutgoing, 0)->ReceiverID());
CScriptNode *pNode = mpScene->ScriptNodeByID(LinkedID);
pNode->GeneratePosition();
mPosition = pNode->AbsolutePosition();
mPosition.z += (pNode->AABox().Size().z / 2.f);
@ -553,9 +558,9 @@ void CScriptNode::GeneratePosition()
{
CVector3f NewPos = CVector3f::skZero;
for (u32 iIn = 0; iIn < mpInstance->NumInLinks(); iIn++)
for (u32 iIn = 0; iIn < mpInstance->NumLinks(eIncoming); iIn++)
{
CScriptNode *pNode = mpScene->ScriptNodeByID(mpInstance->InLink(iIn).ObjectID);
CScriptNode *pNode = mpScene->ScriptNodeByID(mpInstance->Link(eIncoming, iIn)->SenderID());
if (pNode)
{
@ -564,9 +569,9 @@ void CScriptNode::GeneratePosition()
}
}
for (u32 iOut = 0; iOut < mpInstance->NumOutLinks(); iOut++)
for (u32 iOut = 0; iOut < mpInstance->NumLinks(eOutgoing); iOut++)
{
CScriptNode *pNode = mpScene->ScriptNodeByID(mpInstance->OutLink(iOut).ObjectID);
CScriptNode *pNode = mpScene->ScriptNodeByID(mpInstance->Link(eOutgoing, iOut)->ReceiverID());
if (pNode)
{

View File

@ -45,6 +45,7 @@ public:
CColor TintColor(const SViewInfo &ViewInfo) const;
CColor WireframeColor() const;
void LinksModified();
void PropertyModified(IProperty *pProp);
void UpdatePreviewVolume();
void GeneratePosition();

View File

@ -1,5 +1,6 @@
#include "CSplinePathExtra.h"
#include "CWaypointExtra.h"
#include "Core/Resource/Script/CLink.h"
#include "Core/Scene/CScene.h"
CSplinePathExtra::CSplinePathExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent)
@ -45,14 +46,14 @@ void CSplinePathExtra::AddWaypoints()
std::set<CWaypointExtra*> CheckedWaypoints;
for (u32 iLink = 0; iLink < mpInstance->NumOutLinks(); iLink++)
for (u32 iLink = 0; iLink < mpInstance->NumLinks(eOutgoing); iLink++)
{
const SLink& rkLink = mpInstance->OutLink(iLink);
CLink *pLink = mpInstance->Link(eOutgoing, iLink);
if ( (rkLink.State == 0x49533030 && rkLink.Message == 0x41544348) || // InternalState00/Attach
(rkLink.State == 0x4D4F5450 && rkLink.Message == 0x41544348) ) // MotionPath/Attach
if ( (pLink->State() == 0x49533030 && pLink->Message() == 0x41544348) || // InternalState00/Attach
(pLink->State() == 0x4D4F5450 && pLink->Message() == 0x41544348) ) // MotionPath/Attach
{
CScriptNode *pNode = mpScene->ScriptNodeByID(rkLink.ObjectID);
CScriptNode *pNode = mpScene->ScriptNodeByID(pLink->ReceiverID());
if (pNode && pNode->Object()->ObjectTypeID() == 0x57415950) // Waypoint
{

View File

@ -1,4 +1,5 @@
#include "CWaypointExtra.h"
#include "Core/Resource/Script/CLink.h"
#include "Core/Render/CDrawUtil.h"
#include "Core/Render/CRenderer.h"
#include "Core/Scene/CScene.h"
@ -78,13 +79,13 @@ void CWaypointExtra::BuildLinks()
{
mLinks.clear();
for (u32 iLink = 0; iLink < mpInstance->NumOutLinks(); iLink++)
for (u32 iLink = 0; iLink < mpInstance->NumLinks(eOutgoing); iLink++)
{
const SLink& rkLink = mpInstance->OutLink(iLink);
CLink *pLink = mpInstance->Link(eOutgoing, iLink);
if (IsPathLink(rkLink))
if (IsPathLink(pLink))
{
CScriptNode *pNode = mpScene->ScriptNodeByID(rkLink.ObjectID);
CScriptNode *pNode = mpScene->ScriptNodeByID(pLink->ReceiverID());
SWaypointLink Link;
Link.pWaypoint = pNode;
@ -97,26 +98,26 @@ void CWaypointExtra::BuildLinks()
mLinksBuilt = true;
}
bool CWaypointExtra::IsPathLink(const SLink& rkLink)
bool CWaypointExtra::IsPathLink(CLink *pLink)
{
bool Valid = false;
if (rkLink.State < 0xFF)
if (pLink->State() < 0xFF)
{
if (rkLink.State == 0x1 && rkLink.Message == 0x8) Valid = true; // Arrived / Next (MP1)
if (pLink->State() == 0x1 && pLink->Message() == 0x8) Valid = true; // Arrived / Next (MP1)
}
else
{
CFourCC State(rkLink.State);
CFourCC Message(rkLink.Message);
CFourCC State(pLink->State());
CFourCC Message(pLink->Message());
if (State == "ARRV" && Message == "NEXT") Valid = true; // Arrived / Next (MP2)
if (State == "NEXT" && Message == "ATCH") Valid = true; // Next / Attach (MP3/DKCR)
}
if (Valid)
{
CScriptNode *pNode = mpScene->ScriptNodeByID(rkLink.ObjectID);
CScriptNode *pNode = mpScene->ScriptNodeByID(pLink->ReceiverID());
if (pNode)
return pNode->Object()->ObjectTypeID() == mpInstance->ObjectTypeID();

View File

@ -26,7 +26,7 @@ public:
void AddToSplinePath(CSplinePathExtra *pPath);
void RemoveFromSplinePath(CSplinePathExtra *pPath);
void BuildLinks();
bool IsPathLink(const SLink& rkLink);
bool IsPathLink(CLink *pLink);
void GetLinkedWaypoints(std::list<CWaypointExtra*>& rOut);
void LinksModified();

View File

@ -145,7 +145,10 @@ HEADERS += \
WorldEditor/CTemplateEditDialog.h \
WorldEditor/CLinkDialog.h \
WorldEditor/CStateMessageModel.h \
WorldEditor/CSelectInstanceDialog.h
WorldEditor/CSelectInstanceDialog.h \
Undo/CAddLinkCommand.h \
Undo/CDeleteLinksCommand.h \
Undo/CEditLinkCommand.h
# Source Files
SOURCES += \
@ -204,7 +207,10 @@ SOURCES += \
Undo/CChangeLayerCommand.cpp \
WorldEditor/CTemplateEditDialog.cpp \
WorldEditor/CLinkDialog.cpp \
WorldEditor/CSelectInstanceDialog.cpp
WorldEditor/CSelectInstanceDialog.cpp \
Undo/CAddLinkCommand.cpp \
Undo/CDeleteLinksCommand.cpp \
Undo/CEditLinkCommand.cpp
# UI Files
FORMS += \

View File

@ -0,0 +1,35 @@
#include "CAddLinkCommand.h"
#include <Core/Resource/Script/CLink.h>
CAddLinkCommand::CAddLinkCommand(CWorldEditor *pEditor, CLink Link)
: IUndoCommand("Add Link")
, mpEditor(pEditor)
, mLink(Link)
{
mAffectedInstances << mLink.Sender();
if (mLink.Sender() != mLink.Receiver())
mAffectedInstances << mLink.Receiver();
}
void CAddLinkCommand::undo()
{
CScriptObject *pSender = mLink.Sender();
CScriptObject *pReceiver = mLink.Receiver();
u32 SenderIndex = pSender->NumLinks(eOutgoing) - 1;
CLink *pLink = pSender->Link(eOutgoing, SenderIndex);
pSender->RemoveLink(eOutgoing, pLink);
pReceiver->RemoveLink(eIncoming, pLink);
delete pLink;
mpEditor->InstanceLinksModified(mAffectedInstances);
}
void CAddLinkCommand::redo()
{
CLink *pLink = new CLink(mLink);
pLink->Sender()->AddLink(eOutgoing, pLink, -1);
pLink->Receiver()->AddLink(eIncoming, pLink, -1);
mpEditor->InstanceLinksModified(mAffectedInstances);
}

View File

@ -0,0 +1,21 @@
#ifndef CADDLINKCOMMAND_H
#define CADDLINKCOMMAND_H
#include "IUndoCommand.h"
#include "Editor/WorldEditor/CWorldEditor.h"
#include <Core/Resource/Script/CLink.h>
class CAddLinkCommand : public IUndoCommand
{
CWorldEditor *mpEditor;
CLink mLink;
QList<CScriptObject*> mAffectedInstances;
public:
CAddLinkCommand(CWorldEditor *pEditor, CLink Link);
void undo();
void redo();
bool AffectsCleanState() const { return true; }
};
#endif // CADDLINKCOMMAND_H

View File

@ -0,0 +1,97 @@
#include "CDeleteLinksCommand.h"
#include <Core/Resource/Script/CLink.h>
CDeleteLinksCommand::CDeleteLinksCommand(CWorldEditor *pEditor, CScriptObject *pObject, ELinkType Type, const QVector<u32>& rkIndices)
: IUndoCommand("Delete Links")
, mpEditor(pEditor)
{
mAffectedInstances << pObject;
for (int iIdx = 0; iIdx < rkIndices.size(); iIdx++)
{
CLink *pLink = pObject->Link(Type, rkIndices[iIdx]);
SDeletedLink DelLink;
DelLink.State = pLink->State();
DelLink.Message = pLink->Message();
DelLink.pSender = pLink->Sender();
DelLink.pReceiver = pLink->Receiver();
DelLink.SenderIndex = pLink->SenderIndex();
DelLink.ReceiverIndex = pLink->ReceiverIndex();
mLinks << DelLink;
if (Type == eOutgoing)
{
if (!mAffectedInstances.contains(DelLink.pReceiver))
mAffectedInstances << DelLink.pReceiver;
}
else
{
if (!mAffectedInstances.contains(DelLink.pSender))
mAffectedInstances << DelLink.pSender;
}
}
}
void CDeleteLinksCommand::undo()
{
struct SNewLink
{
SDeletedLink *pDelLink;
CLink *pLink;
};
QVector<SNewLink> NewLinks;
for (int iLink = 0; iLink < mLinks.size(); iLink++)
{
SDeletedLink& rDelLink = mLinks[iLink];
SNewLink Link;
Link.pDelLink = &mLinks[iLink];
Link.pLink = new CLink(mpEditor->ActiveArea(), rDelLink.State, rDelLink.Message, rDelLink.pSender->InstanceID(), rDelLink.pReceiver->InstanceID());
NewLinks << Link;
}
// Add to senders
qSort(NewLinks.begin(), NewLinks.end(), [](SNewLink& rLinkA, SNewLink& rLinkB) { return rLinkA.pDelLink->SenderIndex < rLinkB.pDelLink->SenderIndex; });
for (int iLink = 0; iLink < NewLinks.size(); iLink++)
{
SNewLink& rNew = NewLinks[iLink];
rNew.pDelLink->pSender->AddLink(eOutgoing, rNew.pLink, rNew.pDelLink->SenderIndex);
}
// Add to receivers
qSort(NewLinks.begin(), NewLinks.end(), [](SNewLink& rLinkA, SNewLink& rLinkB) { return rLinkA.pDelLink->ReceiverIndex < rLinkB.pDelLink->ReceiverIndex; });
for (int iLink = 0; iLink < NewLinks.size(); iLink++)
{
SNewLink& rNew = NewLinks[iLink];
rNew.pDelLink->pReceiver->AddLink(eIncoming, rNew.pLink, rNew.pDelLink->ReceiverIndex);
}
// Notify world editor
mpEditor->OnLinksModified(mAffectedInstances);
}
void CDeleteLinksCommand::redo()
{
QVector<CLink*> Links;
for (int iLink = 0; iLink < mLinks.size(); iLink++)
{
SDeletedLink& rLink = mLinks[iLink];
Links << rLink.pSender->Link(eOutgoing, rLink.SenderIndex);
}
for (int iLink = 0; iLink < Links.size(); iLink++)
{
CLink *pLink = Links[iLink];
pLink->Sender()->RemoveLink(eOutgoing, pLink);
pLink->Receiver()->RemoveLink(eIncoming, pLink);
delete pLink;
}
// Notify world editor
mpEditor->OnLinksModified(mAffectedInstances);
}

View File

@ -0,0 +1,30 @@
#ifndef CDELETELINKSCOMMAND_H
#define CDELETELINKSCOMMAND_H
#include "IUndoCommand.h"
#include "Editor/WorldEditor/CWorldEditor.h"
class CDeleteLinksCommand : public IUndoCommand
{
CWorldEditor *mpEditor;
QList<CScriptObject*> mAffectedInstances;
struct SDeletedLink
{
u32 State;
u32 Message;
CScriptObject *pSender;
CScriptObject *pReceiver;
u32 SenderIndex;
u32 ReceiverIndex;
};
QVector<SDeletedLink> mLinks;
public:
CDeleteLinksCommand(CWorldEditor *pEditor, CScriptObject *pObject, ELinkType Type, const QVector<u32>& rkIndices);
void undo();
void redo();
bool AffectsCleanState() const { return true; }
};
#endif // CDELETELINKSCOMMAND_H

View File

@ -0,0 +1,50 @@
#include "CEditLinkCommand.h"
CEditLinkCommand::CEditLinkCommand(CWorldEditor *pEditor, CLink *pLink, CLink NewLink)
: IUndoCommand("Edit Link")
, mpEditor(pEditor)
, mpEditLink(pLink)
, mOldLink(*pLink)
, mNewLink(NewLink)
{
mOldSenderIndex = pLink->SenderIndex();
mOldReceiverIndex = pLink->ReceiverIndex();
mAffectedInstances << pLink->Sender();
if (pLink->Receiver() != pLink->Sender()) mAffectedInstances << pLink->Receiver();
if (NewLink.Sender() != pLink->Sender()) mAffectedInstances << NewLink.Sender();
if (NewLink.Receiver() != pLink->Receiver()) mAffectedInstances << NewLink.Receiver();
}
void CEditLinkCommand::undo()
{
if (mOldLink.Sender() != mNewLink.Sender())
{
mNewLink.Sender()->RemoveLink(eOutgoing, mpEditLink);
mOldLink.Sender()->AddLink(eOutgoing, mpEditLink, mOldSenderIndex);
}
if (mOldLink.Receiver() != mNewLink.Receiver())
{
mNewLink.Receiver()->RemoveLink(eIncoming, mpEditLink);
mOldLink.Receiver()->AddLink(eIncoming, mpEditLink, mOldReceiverIndex);
}
*mpEditLink = mOldLink;
mpEditor->OnLinksModified(mAffectedInstances);
}
void CEditLinkCommand::redo()
{
if (mOldLink.Sender() != mNewLink.Sender())
{
mOldLink.Sender()->RemoveLink(eOutgoing, mpEditLink);
mNewLink.Sender()->AddLink(eOutgoing, mpEditLink);
}
if (mOldLink.Receiver() != mNewLink.Receiver())
{
mOldLink.Receiver()->RemoveLink(eIncoming, mpEditLink);
mNewLink.Receiver()->AddLink(eIncoming, mpEditLink);
}
*mpEditLink = mNewLink;
mpEditor->OnLinksModified(mAffectedInstances);
}

View File

@ -0,0 +1,27 @@
#ifndef CEDITLINKCOMMAND_H
#define CEDITLINKCOMMAND_H
#include "IUndoCommand.h"
#include "Editor/WorldEditor/CWorldEditor.h"
#include <Core/Resource/Script/CLink.h>
class CEditLinkCommand : public IUndoCommand
{
CWorldEditor *mpEditor;
CLink *mpEditLink;
CLink mOldLink;
CLink mNewLink;
u32 mOldSenderIndex;
u32 mOldReceiverIndex;
QList<CScriptObject*> mAffectedInstances;
public:
CEditLinkCommand(CWorldEditor *pEditor, CLink *pLink, CLink NewLink);
void undo();
void redo();
bool AffectsCleanState() const { return true; }
};
#endif // CEDITLINKCOMMAND_H

View File

@ -15,6 +15,10 @@
#include "CResizeScriptArrayCommand.h"
#include "CChangeLayerCommand.h"
#include "CAddLinkCommand.h"
#include "CDeleteLinksCommand.h"
#include "CEditLinkCommand.h"
#include "EUndoCommand.h"
#endif // UNDOCOMMANDS

View File

@ -2,6 +2,9 @@
#include "ui_CLinkDialog.h"
#include "CSelectInstanceDialog.h"
#include "CStateMessageModel.h"
#include "CWorldEditor.h"
#include "Editor/Undo/CAddLinkCommand.h"
#include "Editor/Undo/CEditLinkCommand.h"
#include <Core/Resource/Script/CScriptObject.h>
CLinkDialog::CLinkDialog(CWorldEditor *pEditor, QWidget *pParent /*= 0*/)
@ -13,6 +16,7 @@ CLinkDialog::CLinkDialog(CWorldEditor *pEditor, QWidget *pParent /*= 0*/)
, mpReceiver(nullptr)
, mSenderStateModel(CStateMessageModel::eStates, this)
, mReceiverMessageModel(CStateMessageModel::eMessages, this)
, mpEditLink(nullptr)
{
ui->setupUi(this);
ui->SenderStateComboBox->setModel(&mSenderStateModel);
@ -44,6 +48,29 @@ void CLinkDialog::showEvent(QShowEvent *)
SetReceiverNameLabel();
}
void CLinkDialog::NewLink(CScriptObject *pSender, CScriptObject *pReceiver)
{
mpEditLink = nullptr;
SetSender(pSender);
SetReceiver(pReceiver);
if (pSender) ui->SenderStateComboBox->setCurrentIndex(0);
if (pReceiver) ui->ReceiverMessageComboBox->setCurrentIndex(0);
}
void CLinkDialog::EditLink(CLink *pLink)
{
mpEditLink = pLink;
CScriptObject *pSender = pLink->Sender();
CScriptObject *pReceiver = pLink->Receiver();
SetSender(pSender);
SetReceiver(pReceiver);
if (pSender)
ui->SenderStateComboBox->setCurrentIndex(mSenderStateModel.StateIndex(pLink->State()));
if (pReceiver)
ui->ReceiverMessageComboBox->setCurrentIndex(mReceiverMessageModel.MessageIndex(pLink->Message()));
}
void CLinkDialog::SetMaster(CMasterTemplate *pMaster)
{
if (mpMaster != pMaster)
@ -99,7 +126,7 @@ u32 CLinkDialog::State() const
u32 CLinkDialog::Message() const
{
return mReceiverMessageModel.State(ui->ReceiverMessageComboBox->currentIndex());
return mReceiverMessageModel.Message(ui->ReceiverMessageComboBox->currentIndex());
}
void CLinkDialog::SetSenderNameLabel()
@ -127,6 +154,25 @@ void CLinkDialog::SetReceiverNameLabel()
}
// ************ PUBLIC SLOTS ************
void CLinkDialog::accept()
{
CLink Link(mpEditor->ActiveArea(), State(), Message(), Sender()->InstanceID(), Receiver()->InstanceID());
if (!mpEditLink)
{
CAddLinkCommand *pCmd = new CAddLinkCommand(mpEditor, Link);
mpEditor->UndoStack()->push(pCmd);
}
else if (Link != *mpEditLink)
{
CEditLinkCommand *pCmd = new CEditLinkCommand(mpEditor, mpEditLink, Link);
mpEditor->UndoStack()->push(pCmd);
}
QDialog::accept();
}
void CLinkDialog::OnSwapClicked()
{
CScriptObject *pSender = mpReceiver;

View File

@ -2,13 +2,14 @@
#define CLINKDIALOG_H
#include "CStateMessageModel.h"
#include "CWorldEditor.h"
#include <QDialog>
namespace Ui {
class CLinkDialog;
}
class CWorldEditor;
class CLinkDialog : public QDialog
{
Q_OBJECT
@ -17,6 +18,7 @@ class CLinkDialog : public QDialog
CMasterTemplate *mpMaster;
CScriptObject *mpSender;
CScriptObject *mpReceiver;
CLink *mpEditLink;
CStateMessageModel mSenderStateModel;
CStateMessageModel mReceiverMessageModel;
@ -29,6 +31,9 @@ public:
void resizeEvent(QResizeEvent *);
void showEvent(QShowEvent *);
void NewLink(CScriptObject *pSender, CScriptObject *pReceiver);
void EditLink(CLink *pLink);
void SetMaster(CMasterTemplate *pMaster);
void SetSender(CScriptObject *pSender);
void SetReceiver(CScriptObject *pReceiver);
@ -42,6 +47,7 @@ public:
inline CScriptObject* Receiver() const { return mpReceiver; }
public slots:
void accept();
void OnSwapClicked();
void OnPickFromViewportClicked();
void OnPickModeClick(const SRayIntersection& rkHit, QMouseEvent *pEvent);

View File

@ -15,7 +15,7 @@ void CLinkModel::SetObject(CScriptObject *pObj)
emit layoutChanged();
}
void CLinkModel::SetConnectionType(EConnectionType type)
void CLinkModel::SetConnectionType(ELinkType type)
{
mType = type;
emit layoutChanged();
@ -24,12 +24,7 @@ void CLinkModel::SetConnectionType(EConnectionType type)
int CLinkModel::rowCount(const QModelIndex&) const
{
if (mpObject)
{
if (mType == eIncoming)
return mpObject->NumInLinks();
else
return mpObject->NumOutLinks();
}
return mpObject->NumLinks(mType);
else return 0;
}
@ -45,21 +40,22 @@ QVariant CLinkModel::data(const QModelIndex &index, int role) const
else if ((role == Qt::DisplayRole) || (role == Qt::ToolTipRole))
{
SLink link = (mType == eIncoming ? mpObject->InLink(index.row()) : mpObject->OutLink(index.row()));
CLink *pLink = mpObject->Link(mType, index.row());
switch (index.column())
{
case 0: // Column 0 - Target Object
{
CScriptObject *pTargetObj = mpObject->Area()->GetInstanceByID(link.ObjectID);
u32 TargetID = (mType == eIncoming ? pLink->SenderID() : pLink->ReceiverID());
CScriptObject *pTarget = mpObject->Area()->GetInstanceByID(TargetID);
if (pTargetObj) {
QString ObjType = QString("[%1] ").arg(UICommon::ToQString(pTargetObj->Template()->Name()));
return ObjType + UICommon::ToQString(pTargetObj->InstanceName());
if (pTarget) {
QString ObjType = QString("[%1] ").arg(UICommon::ToQString(pTarget->Template()->Name()));
return ObjType + UICommon::ToQString(pTarget->InstanceName());
}
else {
QString strID = QString::number(link.ObjectID, 16);
QString strID = QString::number(TargetID, 16);
while (strID.length() < 8) strID = "0" + strID;
return QString("External: 0x") + strID;
}
@ -67,13 +63,13 @@ QVariant CLinkModel::data(const QModelIndex &index, int role) const
case 1: // Column 1 - State
{
TString StateName = mpObject->MasterTemplate()->StateByID(link.State).Name;
TString StateName = mpObject->MasterTemplate()->StateByID(pLink->State()).Name;
return UICommon::ToQString(StateName);
}
case 2: // Column 2 - Message
{
TString MessageName = mpObject->MasterTemplate()->MessageByID(link.Message).Name;
TString MessageName = mpObject->MasterTemplate()->MessageByID(pLink->Message()).Name;
return UICommon::ToQString(MessageName);
}

View File

@ -8,19 +8,13 @@ class CLinkModel : public QAbstractTableModel
{
Q_OBJECT
public:
enum EConnectionType {
eIncoming, eOutgoing
};
private:
CScriptObject *mpObject;
EConnectionType mType;
ELinkType mType;
public:
explicit CLinkModel(QObject *pParent = 0);
void SetObject(CScriptObject *pObj);
void SetConnectionType(EConnectionType type);
void SetConnectionType(ELinkType type);
int rowCount(const QModelIndex& parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;

View File

@ -91,7 +91,33 @@ public:
endResetModel();
}
void SetScriptTemplate(CScriptTemplate *pScript)
u32 StateIndex(u32 StateID) const
{
if (mType == eMessages) return -1;
for (int iState = 0; iState < mEntries.size(); iState++)
{
if (mEntries[iState].ID == StateID)
return iState;
}
return -1;
}
u32 MessageIndex(u32 MessageID) const
{
if (mType == eStates) return -1;
for (int iMsg = 0; iMsg < mEntries.size(); iMsg++)
{
if (mEntries[iMsg].ID == MessageID)
return iMsg;
}
return -1;
}
inline void SetScriptTemplate(CScriptTemplate *pScript)
{
mpScript = pScript;
}

View File

@ -31,6 +31,7 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
mpArea = nullptr;
mpWorld = nullptr;
mpLinkDialog = new CLinkDialog(this, this);
mpPoiDialog = nullptr;
mGizmoHovering = false;
mGizmoTransforming = false;
@ -108,6 +109,7 @@ void CWorldEditor::closeEvent(QCloseEvent *pEvent)
if (ShouldClose)
{
mUndoStack.clear();
mpLinkDialog->close();
if (mpPoiDialog)
mpPoiDialog->close();
@ -176,6 +178,9 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea, u32 AreaIndex)
CMasterTemplate *pMaster = CMasterTemplate::GetMasterForGame(mpArea->Version());
ui->InstancesTabContents->SetMaster(pMaster);
// Set up dialogs
mpLinkDialog->SetMaster(pMaster);
// Set window title
CStringTable *pWorldNameTable = mpWorld->GetWorldName();
TWideString WorldName = pWorldNameTable ? pWorldNameTable->GetString("ENGL", 0) : "[Untitled World]";
@ -248,6 +253,17 @@ bool CWorldEditor::Save()
}
}
void CWorldEditor::OnLinksModified(const QList<CScriptObject*>& rkInstances)
{
foreach (CScriptObject *pInstance, rkInstances)
{
CScriptNode *pNode = mScene.NodeForObject(pInstance);
pNode->LinksModified();
}
emit InstanceLinksModified(rkInstances);
}
void CWorldEditor::OnPropertyModified(IProperty *pProp)
{
bool EditorProperty = false;

View File

@ -1,6 +1,7 @@
#ifndef CWORLDEDITOR_H
#define CWORLDEDITOR_H
#include "CLinkDialog.h"
#include "CPoiMapEditDialog.h"
#include "Editor/INodeEditor.h"
#include "Editor/CGizmo.h"
@ -35,6 +36,7 @@ class CWorldEditor : public INodeEditor
TResPtr<CGameArea> mpArea;
QTimer mRefreshTimer;
CLinkDialog *mpLinkDialog;
CPoiMapEditDialog *mpPoiDialog;
public:
@ -47,9 +49,11 @@ public:
inline CGameArea* ActiveArea() const { return mpArea; }
inline EGame CurrentGame() const { return mpArea ? mpArea->Version() : eUnknownVersion; }
inline CLinkDialog* LinkDialog() const { return mpLinkDialog; }
public slots:
bool Save();
void OnLinksModified(const QList<CScriptObject*>& rkInstances);
void OnPropertyModified(IProperty *pProp);
void SetSelectionActive(bool Active);
void SetSelectionInstanceNames(const QString& rkNewName, bool IsDone);
@ -101,6 +105,7 @@ signals:
void LayersModified();
void InstancesLayerAboutToChange();
void InstancesLayerChanged(const QList<CScriptNode*>& rkInstanceList);
void InstanceLinksModified(const QList<CScriptObject*>& rkInstances);
void PropertyModified(IProperty *pProp, bool IsEditorProperty);
};

View File

@ -3,6 +3,7 @@
#include "CLinkDialog.h"
#include "CWorldEditor.h"
#include "Editor/Undo/UndoCommands.h"
#include <Core/Scene/CScriptNode.h>
#include <QScrollArea>
@ -20,10 +21,9 @@ WModifyTab::WModifyTab(QWidget *pParent)
ui->PropertyView->header()->setSectionResizeMode(1, QHeaderView::Fixed);
mpInLinkModel = new CLinkModel(this);
mpInLinkModel->SetConnectionType(CLinkModel::eIncoming);
mpInLinkModel->SetConnectionType(eIncoming);
mpOutLinkModel = new CLinkModel(this);
mpOutLinkModel->SetConnectionType(CLinkModel::eOutgoing);
mpLinkDialog = nullptr;
mpOutLinkModel->SetConnectionType(eOutgoing);
ui->InLinksTableView->setModel(mpInLinkModel);
ui->OutLinksTableView->setModel(mpOutLinkModel);
@ -31,10 +31,14 @@ WModifyTab::WModifyTab(QWidget *pParent)
ui->OutLinksTableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
connect(ui->InLinksTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnLinkTableDoubleClick(QModelIndex)));
connect(ui->OutLinksTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnLinkTableDoubleClick(QModelIndex)));
connect(ui->InLinksTableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(OnIncomingLinksSelectionModified()));
connect(ui->OutLinksTableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(OnOutgoingLinksSelectionModified()));
connect(ui->AddOutgoingConnectionButton, SIGNAL(clicked()), this, SLOT(OnAddOutgoingLinkClicked()));
connect(ui->AddIncomingConnectionButton, SIGNAL(clicked()), this, SLOT(OnAddIncomingLinkClicked()));
connect(ui->DeleteOutgoingConnectionButton, SIGNAL(clicked()), this, SLOT(OnDeleteOutgoingLinkClicked()));
connect(ui->DeleteIncomingConnectionButton, SIGNAL(clicked()), this, SLOT(OnDeleteIncomingLinkClicked()));
connect(ui->EditOutgoingConnectionButton, SIGNAL(clicked()), this, SLOT(OnEditOutgoingLinkClicked()));
connect(ui->EditIncomingConnectionButton, SIGNAL(clicked()), this, SLOT(OnEditIncomingLinkClicked()));
ClearUI();
}
@ -48,8 +52,8 @@ void WModifyTab::SetEditor(CWorldEditor *pEditor)
{
mpWorldEditor = pEditor;
ui->PropertyView->SetEditor(mpWorldEditor);
connect(mpWorldEditor, SIGNAL(Closed()), this, SLOT(OnWorldEditorClosed()));
connect(mpWorldEditor, SIGNAL(SelectionTransformed()), this, SLOT(OnWorldSelectionTransformed()));
connect(mpWorldEditor, SIGNAL(InstanceLinksModified(const QList<CScriptObject*>&)), this, SLOT(OnInstanceLinksModified(const QList<CScriptObject*>&)));
}
void WModifyTab::GenerateUI(QList<CSceneNode*>& Selection)
@ -69,9 +73,12 @@ void WModifyTab::GenerateUI(QList<CSceneNode*>& Selection)
// Set up UI
ui->PropertyView->SetInstance(pObj);
ui->LightGroupBox->hide();
ui->InLinksTableView->clearSelection();
ui->OutLinksTableView->clearSelection();
mpInLinkModel->SetObject(pObj);
mpOutLinkModel->SetObject(pObj);
ui->LightGroupBox->hide();
}
}
}
@ -88,36 +95,21 @@ void WModifyTab::ClearUI()
mpSelectedNode = nullptr;
}
void WModifyTab::CreateLinkDialog()
// ************ PUBLIC SLOTS ************
void WModifyTab::OnInstanceLinksModified(const QList<CScriptObject*>& rkInstances)
{
if (!mpLinkDialog)
{
mpLinkDialog = new CLinkDialog(mpWorldEditor, this);
if (mpSelectedNode && mpSelectedNode->NodeType() == eScriptNode)
{
CScriptNode *pScript = static_cast<CScriptNode*>(mpSelectedNode);
mpLinkDialog->SetMaster(pScript->Object()->MasterTemplate());
}
CScriptObject *pInstance = static_cast<CScriptNode*>(mpSelectedNode)->Object();
connect(mpLinkDialog, SIGNAL(accepted()), this, SLOT(OnLinkDialogAccept()));
connect(mpLinkDialog, SIGNAL(rejected()), this, SLOT(OnLinkDialogReject()));
}
}
void WModifyTab::DeleteLinkDialog()
if (pInstance && rkInstances.contains(pInstance))
{
if (mpLinkDialog)
{
delete mpLinkDialog;
mpLinkDialog = nullptr;
mpInLinkModel->layoutChanged();
mpOutLinkModel->layoutChanged();
ui->InLinksTableView->clearSelection();
ui->OutLinksTableView->clearSelection();
}
}
// ************ PUBLIC SLOTS ************
void WModifyTab::OnWorldEditorClosed()
{
DeleteLinkDialog();
}
void WModifyTab::OnWorldSelectionTransformed()
@ -125,20 +117,26 @@ void WModifyTab::OnWorldSelectionTransformed()
ui->PropertyView->UpdateEditorProperties(QModelIndex());
}
void WModifyTab::OnOutgoingLinksSelectionModified()
{
u32 NumSelectedRows = ui->OutLinksTableView->selectionModel()->selectedRows().size();
ui->EditOutgoingConnectionButton->setEnabled(NumSelectedRows == 1);
}
void WModifyTab::OnIncomingLinksSelectionModified()
{
u32 NumSelectedRows = ui->InLinksTableView->selectionModel()->selectedRows().size();
ui->EditIncomingConnectionButton->setEnabled(NumSelectedRows == 1);
}
void WModifyTab::OnAddOutgoingLinkClicked()
{
if (mpSelectedNode && mpSelectedNode->NodeType() == eScriptNode)
{
CScriptObject *pInst = static_cast<CScriptNode*>(mpSelectedNode)->Object();
CreateLinkDialog();
if (mpLinkDialog->Sender() != pInst)
{
mpLinkDialog->SetSender(pInst);
mpLinkDialog->SetReceiver(nullptr);
}
mpLinkDialog->show();
CLinkDialog *pDialog = mpWorldEditor->LinkDialog();
pDialog->NewLink(pInst, nullptr);
pDialog->show();
}
}
@ -147,34 +145,82 @@ void WModifyTab::OnAddIncomingLinkClicked()
if (mpSelectedNode && mpSelectedNode->NodeType() == eScriptNode)
{
CScriptObject *pInst = static_cast<CScriptNode*>(mpSelectedNode)->Object();
CreateLinkDialog();
if (mpLinkDialog->Receiver() != pInst)
{
mpLinkDialog->SetSender(nullptr);
mpLinkDialog->SetReceiver(pInst);
}
mpLinkDialog->show();
CLinkDialog *pDialog = mpWorldEditor->LinkDialog();
pDialog->NewLink(nullptr, pInst);
pDialog->show();
}
}
void WModifyTab::OnDeleteOutgoingLinkClicked()
{
if (mpSelectedNode && mpSelectedNode->NodeType() == eScriptNode)
{
QModelIndexList SelectedIndices = ui->OutLinksTableView->selectionModel()->selectedRows();
if (!SelectedIndices.isEmpty())
{
QVector<u32> Indices;
for (int iIdx = 0; iIdx < SelectedIndices.size(); iIdx++)
Indices << SelectedIndices[iIdx].row();
CScriptObject *pInst = static_cast<CScriptNode*>(mpSelectedNode)->Object();
CDeleteLinksCommand *pCmd = new CDeleteLinksCommand(mpWorldEditor, pInst, eOutgoing, Indices);
mpWorldEditor->UndoStack()->push(pCmd);
}
}
}
void WModifyTab::OnDeleteIncomingLinkClicked()
{
if (mpSelectedNode && mpSelectedNode->NodeType() == eScriptNode)
{
QModelIndexList SelectedIndices = ui->InLinksTableView->selectionModel()->selectedRows();
if (!SelectedIndices.isEmpty())
{
QVector<u32> Indices;
for (int iIdx = 0; iIdx < SelectedIndices.size(); iIdx++)
Indices << SelectedIndices[iIdx].row();
CScriptObject *pInst = static_cast<CScriptNode*>(mpSelectedNode)->Object();
CDeleteLinksCommand *pCmd = new CDeleteLinksCommand(mpWorldEditor, pInst, eIncoming, Indices);
mpWorldEditor->UndoStack()->push(pCmd);
}
}
}
void WModifyTab::OnLinkDialogAccept()
void WModifyTab::OnEditOutgoingLinkClicked()
{
DeleteLinkDialog();
if (mpSelectedNode && mpSelectedNode->NodeType() == eScriptNode)
{
QModelIndexList SelectedIndices = ui->OutLinksTableView->selectionModel()->selectedRows();
if (SelectedIndices.size() == 1)
{
CScriptObject *pInst = static_cast<CScriptNode*>(mpSelectedNode)->Object();
CLinkDialog *pDialog = mpWorldEditor->LinkDialog();
pDialog->EditLink(pInst->Link(eOutgoing, SelectedIndices.front().row()));
pDialog->show();
}
}
}
void WModifyTab::OnLinkDialogReject()
void WModifyTab::OnEditIncomingLinkClicked()
{
DeleteLinkDialog();
if (mpSelectedNode && mpSelectedNode->NodeType() == eScriptNode)
{
QModelIndexList SelectedIndices = ui->InLinksTableView->selectionModel()->selectedRows();
if (SelectedIndices.size() == 1)
{
CScriptObject *pInst = static_cast<CScriptNode*>(mpSelectedNode)->Object();
CLinkDialog *pDialog = mpWorldEditor->LinkDialog();
pDialog->EditLink(pInst->Link(eIncoming, SelectedIndices.front().row()));
pDialog->show();
}
}
}
// ************ PRIVATE SLOTS ************
@ -184,14 +230,14 @@ void WModifyTab::OnLinkTableDoubleClick(QModelIndex Index)
{
// The link table will only be visible if the selected node is a script node
CScriptNode *pNode = static_cast<CScriptNode*>(mpSelectedNode);
SLink Link;
u32 InstanceID;
if (sender() == ui->InLinksTableView)
Link = pNode->Object()->InLink(Index.row());
InstanceID = pNode->Object()->Link(eIncoming, Index.row())->SenderID();
else if (sender() == ui->OutLinksTableView)
Link = pNode->Object()->OutLink(Index.row());
InstanceID = pNode->Object()->Link(eOutgoing, Index.row())->ReceiverID();
CScriptNode *pLinkedNode = pNode->Scene()->ScriptNodeByID(Link.ObjectID);
CScriptNode *pLinkedNode = pNode->Scene()->ScriptNodeByID(InstanceID);
if (pLinkedNode)
{

View File

@ -28,28 +28,25 @@ class WModifyTab : public QWidget
CLinkModel *mpInLinkModel;
CLinkModel *mpOutLinkModel;
CLinkDialog *mpLinkDialog;
public:
explicit WModifyTab(QWidget *pParent = 0);
~WModifyTab();
void SetEditor(CWorldEditor *pEditor);
void GenerateUI(QList<CSceneNode*>& Selection);
void ClearUI();
void CreateLinkDialog();
void DeleteLinkDialog();
public slots:
void OnWorldEditorClosed();
void OnInstanceLinksModified(const QList<CScriptObject*>& rkInstances);
void OnWorldSelectionTransformed();
void OnOutgoingLinksSelectionModified();
void OnIncomingLinksSelectionModified();
void OnAddOutgoingLinkClicked();
void OnAddIncomingLinkClicked();
void OnDeleteOutgoingLinkClicked();
void OnDeleteIncomingLinkClicked();
void OnLinkDialogAccept();
void OnLinkDialogReject();
void OnEditOutgoingLinkClicked();
void OnEditIncomingLinkClicked();
private:
Ui::WModifyTab *ui;

View File

@ -127,11 +127,14 @@
<item>
<widget class="QTableView" name="OutLinksTableView">
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
<enum>QAbstractScrollArea::AdjustIgnored</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
@ -173,6 +176,28 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="EditOutgoingConnectionButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item>
<spacer name="OutgoingButtonsSpacer">
<property name="orientation">
@ -205,6 +230,18 @@
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTableView" name="InLinksTableView">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>75</number>
</attribute>
@ -237,6 +274,22 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="EditIncomingConnectionButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximumSize">
<size>
<width>39</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item>
<spacer name="IncomingButtonsSpacer">
<property name="orientation">