Added Editor Properties widget at the top of every World Editor tab, made tons of backend changes to get it to work properly

This commit is contained in:
parax0 2016-02-07 23:48:43 -07:00
parent 8e1b66fa5a
commit a46cd5446f
49 changed files with 930 additions and 299 deletions

View File

@ -218,7 +218,6 @@ SOURCES += \
Resource/Model/CStaticModel.cpp \ Resource/Model/CStaticModel.cpp \
Resource/Model/SSurface.cpp \ Resource/Model/SSurface.cpp \
Resource/Script/CMasterTemplate.cpp \ Resource/Script/CMasterTemplate.cpp \
Resource/Script/CScriptLayer.cpp \
Resource/Script/CScriptObject.cpp \ Resource/Script/CScriptObject.cpp \
Resource/Script/CScriptTemplate.cpp \ Resource/Script/CScriptTemplate.cpp \
Resource/CAnimationParameters.cpp \ Resource/CAnimationParameters.cpp \

View File

@ -116,11 +116,11 @@ void CScriptCooker::WriteLayerMP1(CScriptLayer *pLayer)
{ {
u32 LayerStart = mpSCLY->Tell(); u32 LayerStart = mpSCLY->Tell();
mpSCLY->WriteByte(0); // Unknown value mpSCLY->WriteByte(0); // Unknown value
mpSCLY->WriteLong(pLayer->GetNumObjects()); mpSCLY->WriteLong(pLayer->NumInstances());
for (u32 iInst = 0; iInst < pLayer->GetNumObjects(); iInst++) for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
{ {
CScriptObject *pInstance = pLayer->ObjectByIndex(iInst); CScriptObject *pInstance = pLayer->InstanceByIndex(iInst);
WriteInstanceMP1(pInstance); WriteInstanceMP1(pInstance);
} }

View File

@ -572,7 +572,7 @@ void CAreaLoader::SetUpObjects()
if (!pLayer) break; if (!pLayer) break;
} }
for (u32 iObj = 0; iObj < pLayer->GetNumObjects(); iObj++) for (u32 iObj = 0; iObj < pLayer->NumInstances(); iObj++)
{ {
// Add object to object map // Add object to object map
CScriptObject *pObj = (*pLayer)[iObj]; CScriptObject *pObj = (*pLayer)[iObj];

View File

@ -123,11 +123,11 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY)
case eArrayProperty: { case eArrayProperty: {
CArrayProperty *pArrayCast = static_cast<CArrayProperty*>(pProp); CArrayProperty *pArrayCast = static_cast<CArrayProperty*>(pProp);
u32 Size = SCLY.ReadLong(); int Size = SCLY.ReadLong();
pArrayCast->Resize(Size); pArrayCast->Resize(Size);
for (u32 iElem = 0; iElem < Size; iElem++) for (int iElem = 0; iElem < Size; iElem++)
{ {
if (mVersion < eEchoesDemo) if (mVersion < eEchoesDemo)
LoadStructMP1(SCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate()); LoadStructMP1(SCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate());
@ -243,7 +243,7 @@ CScriptLayer* CScriptLoader::LoadLayerMP1(IInputStream &SCLY)
{ {
CScriptObject *pObj = LoadObjectMP1(SCLY); CScriptObject *pObj = LoadObjectMP1(SCLY);
if (pObj) if (pObj)
mpLayer->AddObject(pObj); mpLayer->AddInstance(pObj);
} }
// Layer sizes are always a multiple of 32 - skip end padding before returning // Layer sizes are always a multiple of 32 - skip end padding before returning
@ -391,7 +391,7 @@ CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& SCLY)
{ {
CScriptObject *pObj = LoadObjectMP2(SCLY); CScriptObject *pObj = LoadObjectMP2(SCLY);
if (pObj) if (pObj)
mpLayer->AddObject(pObj); mpLayer->AddInstance(pObj);
} }
if (IsSCGN) if (IsSCGN)

View File

@ -1,95 +0,0 @@
#include "CScriptLayer.h"
CScriptLayer::CScriptLayer()
{
mLayerName = "New Layer";
mActive = true;
mVisible = true;
}
CScriptLayer::~CScriptLayer()
{
for (auto it = mObjects.begin(); it != mObjects.end(); it++)
delete *it;
}
// ************* DATA MANIPULATION *************
void CScriptLayer::AddObject(CScriptObject* object)
{
mObjects.push_back(object);
}
void CScriptLayer::DeleteObjectByIndex(u32 index)
{
delete mObjects[index];
mObjects.erase(mObjects.begin() + index, mObjects.begin() + index);
}
void CScriptLayer::DeleteObjectByID(u32 ID)
{
for (auto it = mObjects.begin(); it != mObjects.end(); it++)
{
if ((*it)->InstanceID() == ID)
{
delete *it;
mObjects.erase(it, it);
break;
}
}
}
void CScriptLayer::Reserve(u32 amount)
{
mObjects.reserve(amount);
}
// ************* GETTERS *************
TString CScriptLayer::Name()
{
return mLayerName;
}
bool CScriptLayer::IsActive()
{
return mActive;
}
bool CScriptLayer::IsVisible()
{
return mVisible;
}
u32 CScriptLayer::GetNumObjects()
{
return mObjects.size();
}
CScriptObject* CScriptLayer::ObjectByIndex(u32 index)
{
return mObjects[index];
}
CScriptObject* CScriptLayer::ObjectByID(u32 ID)
{
for (auto it = mObjects.begin(); it != mObjects.end(); it++)
if ((*it)->InstanceID() == ID)
return *it;
return nullptr;
}
// ************* SETTERS *************
void CScriptLayer::SetName(const TString& name)
{
mLayerName = name;
}
void CScriptLayer::SetActive(bool active)
{
mActive = active;
}
void CScriptLayer::SetVisible(bool visible)
{
mVisible = visible;
}

View File

@ -1,5 +1,5 @@
#ifndef SSCRIPTLAYER_H #ifndef CSCRIPTLAYER_H
#define SSCRIPTLAYER_H #define CSCRIPTLAYER_H
#include "CScriptObject.h" #include "CScriptObject.h"
#include <Common/types.h> #include <Common/types.h>
@ -11,38 +11,85 @@ class CScriptLayer
TString mLayerName; TString mLayerName;
bool mActive; bool mActive;
bool mVisible; bool mVisible;
std::vector<CScriptObject*> mObjects; std::vector<CScriptObject*> mInstances;
public: public:
CScriptLayer(); CScriptLayer()
~CScriptLayer(); : mLayerName("New Layer")
, mActive(true)
// Data Manipulation , mVisible(true)
void AddObject(CScriptObject* object);
void DeleteObjectByIndex(u32 index);
void DeleteObjectByID(u32 ID);
void Reserve(u32 amount);
// Getters and Setters
TString Name();
bool IsActive();
bool IsVisible();
u32 GetNumObjects();
CScriptObject* ObjectByIndex(u32 index);
CScriptObject* ObjectByID(u32 ID);
void SetName(const TString& name);
void SetActive(bool active);
void SetVisible(bool visible);
// Operators
CScriptObject* operator[](u32 index);
};
// ************* INLINE FUNCTIONS *************
inline CScriptObject* CScriptLayer::operator[](u32 index)
{ {
return mObjects[index];
} }
~CScriptLayer()
{
for (auto it = mInstances.begin(); it != mInstances.end(); it++)
delete *it;
}
#endif // SSCRIPTLAYER_H // Data Manipulation
void AddInstance(CScriptObject *pObject)
{
mInstances.push_back(pObject);
}
void RemoveInstance(CScriptObject *pInstance)
{
for (auto it = mInstances.begin(); it != mInstances.end(); it++)
{
if (*it == pInstance)
{
mInstances.erase(it);
break;
}
}
}
void RemoveInstanceByIndex(u32 Index)
{
mInstances.erase(mInstances.begin() + Index);
}
void RemoveInstanceByID(u32 ID)
{
for (auto it = mInstances.begin(); it != mInstances.end(); it++)
{
if ((*it)->InstanceID() == ID)
{
mInstances.erase(it);
break;
}
}
}
void Reserve(u32 Amount)
{
mInstances.reserve(Amount);
}
// Accessors
inline TString Name() const { return mLayerName; }
inline bool IsActive() const { return mActive; }
inline bool IsVisible() const { return mVisible; }
inline u32 NumInstances() const { return mInstances.size(); }
inline CScriptObject* InstanceByIndex(u32 Index) const { return mInstances[Index]; }
inline CScriptObject* InstanceByID(u32 ID) const
{
for (auto it = mInstances.begin(); it != mInstances.end(); it++)
{
if ((*it)->InstanceID() == ID)
return *it;
}
return nullptr;
}
inline void SetName(const TString& rkName) { mLayerName = rkName; }
inline void SetActive(bool Active) { mActive = Active; }
inline void SetVisible(bool Visible) { mVisible = Visible; }
// Operators
CScriptObject* operator[](u32 Index) { return InstanceByIndex(Index); }
};
#endif // CSCRIPTLAYER_H

View File

@ -1,4 +1,5 @@
#include "CScriptObject.h" #include "CScriptObject.h"
#include "CScriptLayer.h"
#include "CMasterTemplate.h" #include "CMasterTemplate.h"
#include "Core/Resource/CAnimSet.h" #include "Core/Resource/CAnimSet.h"
@ -69,6 +70,16 @@ bool CScriptObject::IsEditorProperty(IProperty *pProp)
); );
} }
void CScriptObject::SetLayer(CScriptLayer *pLayer)
{
if (pLayer != mpLayer)
{
mpLayer->RemoveInstance(this);
mpLayer = pLayer;
mpLayer->AddInstance(this);
}
}
// ************ GETTERS ************ // ************ GETTERS ************
IProperty* CScriptObject::PropertyByIndex(u32 index) const IProperty* CScriptObject::PropertyByIndex(u32 index) const
{ {

View File

@ -50,6 +50,7 @@ public:
void EvaluateCollisionModel(); void EvaluateCollisionModel();
void EvaluateVolume(); void EvaluateVolume();
bool IsEditorProperty(IProperty *pProp); bool IsEditorProperty(IProperty *pProp);
void SetLayer(CScriptLayer *pLayer);
CScriptTemplate* Template() const; CScriptTemplate* Template() const;
CMasterTemplate* MasterTemplate() const; CMasterTemplate* MasterTemplate() const;
@ -84,6 +85,12 @@ public:
CCollisionMeshGroup* GetCollision() const; CCollisionMeshGroup* GetCollision() const;
EVolumeShape VolumeShape() const; EVolumeShape VolumeShape() const;
float VolumeScale() const; float VolumeScale() const;
TStringProperty* InstanceNameProperty() const { return mpInstanceName; }
TVector3Property* PositionProperty() const { return mpPosition; }
TVector3Property* RotationProperty() const { return mpRotation; }
TVector3Property* ScaleProperty() const { return mpScale; }
TBoolProperty* ActiveProperty() const { return mpActive; }
}; };
#endif // CSCRIPTOBJECT_H #endif // CSCRIPTOBJECT_H

View File

@ -2,6 +2,11 @@
#include "IPropertyTemplate.h" #include "IPropertyTemplate.h"
// ************ IProperty ************ // ************ IProperty ************
CPropertyStruct* IProperty::RootStruct()
{
return (mpParent ? mpParent->RootStruct() : Type() == eStructProperty ? static_cast<CPropertyStruct*>(this) : nullptr);
}
IPropertyTemplate* IProperty::Template() const IPropertyTemplate* IProperty::Template() const
{ {
return mpTemplate; return mpTemplate;
@ -111,23 +116,23 @@ CPropertyStruct* CPropertyStruct::StructByIDString(const TIDString& rkStr) const
} }
// ************ CArrayProperty ************ // ************ CArrayProperty ************
void CArrayProperty::Resize(u32 Size) void CArrayProperty::Resize(int Size)
{ {
u32 OldSize = mProperties.size(); int OldSize = mProperties.size();
if (OldSize == Size) return; if (OldSize == Size) return;
if (Size < OldSize) if (Size < OldSize)
{ {
for (u32 i = mProperties.size() - 1; i >= Size; i--) for (int iProp = mProperties.size() - 1; iProp >= Size; iProp--)
delete mProperties[i]; delete mProperties[iProp];
} }
mProperties.resize(Size); mProperties.resize(Size);
if (Size > OldSize) if (Size > OldSize)
{ {
for (u32 i = OldSize; i < Size; i++) for (int iProp = OldSize; iProp < Size; iProp++)
mProperties[i] = static_cast<CArrayTemplate*>(mpTemplate)->CreateSubStruct(this); mProperties[iProp] = static_cast<CArrayTemplate*>(mpTemplate)->CreateSubStruct(this);
} }
} }

View File

@ -47,6 +47,8 @@ public:
inline CPropertyStruct* Parent() const { return mpParent; } inline CPropertyStruct* Parent() const { return mpParent; }
inline void SetParent(CPropertyStruct *pParent) { mpParent = pParent; } inline void SetParent(CPropertyStruct *pParent) { mpParent = pParent; }
CPropertyStruct* RootStruct();
// These functions can't be in the header to avoid circular includes with IPropertyTemplate.h // These functions can't be in the header to avoid circular includes with IPropertyTemplate.h
IPropertyTemplate* Template() const; IPropertyTemplate* Template() const;
TString Name() const; TString Name() const;
@ -178,7 +180,7 @@ public:
inline void Reserve(u32 amount) { mProperties.reserve(amount); } inline void Reserve(u32 amount) { mProperties.reserve(amount); }
// Functions // Functions
void Resize(u32 Size); void Resize(int Size);
CStructTemplate* SubStructTemplate() const; CStructTemplate* SubStructTemplate() const;
TString ElementName() const; TString ElementName() const;
}; };

View File

@ -116,12 +116,12 @@ void CScene::SetActiveArea(CGameArea *pArea)
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++) for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
{ {
CScriptLayer *pLayer = mpArea->GetScriptLayer(iLyr); CScriptLayer *pLayer = mpArea->GetScriptLayer(iLyr);
u32 NumObjects = pLayer->GetNumObjects(); u32 NumObjects = pLayer->NumInstances();
mNodes[eScriptNode].reserve(mNodes[eScriptNode].size() + NumObjects); mNodes[eScriptNode].reserve(mNodes[eScriptNode].size() + NumObjects);
for (u32 iObj = 0; iObj < NumObjects; iObj++) for (u32 iObj = 0; iObj < NumObjects; iObj++)
{ {
CScriptObject *pObj = pLayer->ObjectByIndex(iObj); CScriptObject *pObj = pLayer->InstanceByIndex(iObj);
CScriptNode *pNode = CreateScriptNode(pObj); CScriptNode *pNode = CreateScriptNode(pObj);
pNode->BuildLightList(mpArea); pNode->BuildLightList(mpArea);
@ -142,9 +142,9 @@ void CScene::SetActiveArea(CGameArea *pArea)
CScriptLayer *pGenLayer = mpArea->GetGeneratorLayer(); CScriptLayer *pGenLayer = mpArea->GetGeneratorLayer();
if (pGenLayer) if (pGenLayer)
{ {
for (u32 iObj = 0; iObj < pGenLayer->GetNumObjects(); iObj++) for (u32 iObj = 0; iObj < pGenLayer->NumInstances(); iObj++)
{ {
CScriptObject *pObj = pGenLayer->ObjectByIndex(iObj); CScriptObject *pObj = pGenLayer->InstanceByIndex(iObj);
CScriptNode *pNode = CreateScriptNode(pObj); CScriptNode *pNode = CreateScriptNode(pObj);
// Add to map // Add to map

View File

@ -191,6 +191,8 @@ void CScriptNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewIn
{ {
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ZERO); glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ZERO);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
CGraphics::UpdateVertexBlock();
CGraphics::UpdatePixelBlock();
CDrawUtil::DrawShadedCube(CColor::skTransparentPurple * TintColor(ViewInfo)); CDrawUtil::DrawShadedCube(CColor::skTransparentPurple * TintColor(ViewInfo));
} }
} }

View File

@ -137,7 +137,9 @@ HEADERS += \
Undo/CEditScriptPropertyCommand.h \ Undo/CEditScriptPropertyCommand.h \
Undo/CResizeScriptArrayCommand.h \ Undo/CResizeScriptArrayCommand.h \
Undo/CBasicPropertyCommand.h \ Undo/CBasicPropertyCommand.h \
Undo/IUndoCommand.h Undo/IUndoCommand.h \
WorldEditor/WEditorProperties.h \
Undo/CChangeLayerCommand.h
# Source Files # Source Files
SOURCES += \ SOURCES += \
@ -191,7 +193,9 @@ SOURCES += \
WorldEditor/CInstancesModel.cpp \ WorldEditor/CInstancesModel.cpp \
Undo/CEditScriptPropertyCommand.cpp \ Undo/CEditScriptPropertyCommand.cpp \
Undo/CResizeScriptArrayCommand.cpp \ Undo/CResizeScriptArrayCommand.cpp \
Undo/CBasicPropertyCommand.cpp Undo/CBasicPropertyCommand.cpp \
WorldEditor/WEditorProperties.cpp \
Undo/CChangeLayerCommand.cpp
# UI Files # UI Files
FORMS += \ FORMS += \

View File

@ -21,7 +21,7 @@
#define CONNECT_RELAY(Widget, Index, Signal) \ #define CONNECT_RELAY(Widget, Index, Signal) \
CPropertyRelay *pRelay = new CPropertyRelay(Widget, Index); \ CPropertyRelay *pRelay = new CPropertyRelay(Widget, Index); \
connect(Widget, SIGNAL(Signal), pRelay, SLOT(OnWidgetEdited())); \ connect(Widget, SIGNAL(Signal), pRelay, SLOT(OnWidgetEdited())); \
connect(pRelay, SIGNAL(WidgetEdited(QWidget*, const QModelIndex&)), this, SLOT(WidgetEdited(QWidget*, const QModelIndex&))); connect(pRelay, SIGNAL(WidgetEdited(QWidget*, const QModelIndex&)), this, SLOT(WidgetEdited(QWidget*, const QModelIndex&)))
CPropertyDelegate::CPropertyDelegate(QObject *pParent /*= 0*/) CPropertyDelegate::CPropertyDelegate(QObject *pParent /*= 0*/)
: QStyledItemDelegate(pParent) : QStyledItemDelegate(pParent)
@ -57,7 +57,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
case eBoolProperty: case eBoolProperty:
{ {
QCheckBox *pCheckBox = new QCheckBox(pParent); QCheckBox *pCheckBox = new QCheckBox(pParent);
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool)) CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool));
pOut = pCheckBox; pOut = pCheckBox;
break; break;
} }
@ -67,7 +67,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT16_MIN); pSpinBox->setMinimum(INT16_MIN);
pSpinBox->setMaximum(INT16_MAX); pSpinBox->setMaximum(INT16_MAX);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)) CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int));
pOut = pSpinBox; pOut = pSpinBox;
break; break;
} }
@ -77,7 +77,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT32_MIN); pSpinBox->setMinimum(INT32_MIN);
pSpinBox->setMaximum(INT32_MAX); pSpinBox->setMaximum(INT32_MAX);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)) CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int));
pOut = pSpinBox; pOut = pSpinBox;
break; break;
} }
@ -86,15 +86,15 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
{ {
WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent); WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent);
pSpinBox->setSingleStep(0.1); pSpinBox->setSingleStep(0.1);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double));
pOut = pSpinBox; pOut = pSpinBox;
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
break; break;
} }
case eColorProperty: case eColorProperty:
{ {
WColorPicker *pColorPicker = new WColorPicker(pParent); WColorPicker *pColorPicker = new WColorPicker(pParent);
CONNECT_RELAY(pColorPicker, rkIndex, colorChanged(QColor)) CONNECT_RELAY(pColorPicker, rkIndex, colorChanged(QColor));
pOut = pColorPicker; pOut = pColorPicker;
break; break;
} }
@ -102,7 +102,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
case eStringProperty: case eStringProperty:
{ {
QLineEdit *pLineEdit = new QLineEdit(pParent); QLineEdit *pLineEdit = new QLineEdit(pParent);
CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString)) CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString));
pOut = pLineEdit; pOut = pLineEdit;
break; break;
} }
@ -116,7 +116,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
for (u32 iEnum = 0; iEnum < pTemp->NumEnumerators(); iEnum++) for (u32 iEnum = 0; iEnum < pTemp->NumEnumerators(); iEnum++)
pComboBox->addItem(TO_QSTRING(pTemp->EnumeratorName(iEnum))); pComboBox->addItem(TO_QSTRING(pTemp->EnumeratorName(iEnum)));
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int)) CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int));
pOut = pComboBox; pOut = pComboBox;
break; break;
} }
@ -128,7 +128,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
pSelector->SetAllowedExtensions(pTemp->Extensions()); pSelector->SetAllowedExtensions(pTemp->Extensions());
pSelector->setFont(qobject_cast<QWidget*>(parent())->font()); // bit of a hack to stop the resource selector font from changing pSelector->setFont(qobject_cast<QWidget*>(parent())->font()); // bit of a hack to stop the resource selector font from changing
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString)) CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString));
pOut = pSelector; pOut = pSelector;
break; break;
} }
@ -159,7 +159,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
else if (pProp->Type() == eBitfieldProperty) else if (pProp->Type() == eBitfieldProperty)
{ {
QCheckBox *pCheckBox = new QCheckBox(pParent); QCheckBox *pCheckBox = new QCheckBox(pParent);
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool)) CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool));
pOut = pCheckBox; pOut = pCheckBox;
} }
@ -178,7 +178,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
pSpinBox->setMaximum(1.0); pSpinBox->setMaximum(1.0);
} }
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double)) CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double));
pOut = pSpinBox; pOut = pSpinBox;
} }
} }
@ -194,6 +194,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkIndex) const void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkIndex) const
{ {
BlockRelays(true); BlockRelays(true);
mEditInProgress = false; // fixes case where user does undo mid-edit
if (pEditor) if (pEditor)
{ {
@ -433,11 +434,11 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
{ {
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor); WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp); CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
u32 NewCount = pSpinBox->value(); int NewCount = pSpinBox->value();
if (pArray->Count() != NewCount) if (pArray->Count() != NewCount)
{ {
CResizeScriptArrayCommand *pCmd = new CResizeScriptArrayCommand(mpModel, rkIndex, NewCount); CResizeScriptArrayCommand *pCmd = new CResizeScriptArrayCommand(pProp, mpEditor, mpModel, NewCount);
mpEditor->UndoStack()->push(pCmd); mpEditor->UndoStack()->push(pCmd);
} }
break; break;
@ -517,7 +518,8 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
// Create undo command // Create undo command
if (!Matches || EditInProgress) if (!Matches || EditInProgress)
{ {
CEditScriptPropertyCommand *pCommand = new CEditScriptPropertyCommand(mpModel, rkIndex, pOldValue, !mEditInProgress); // Always consider the edit done for bool properties
CEditScriptPropertyCommand *pCommand = new CEditScriptPropertyCommand(pProp, mpEditor, pOldValue, (!mEditInProgress || pProp->Type() == eBoolProperty));
mpEditor->UndoStack()->push(pCommand); mpEditor->UndoStack()->push(pCommand);
} }
@ -563,7 +565,7 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
else else
pSelector->SetAllowedExtensions("CHAR"); pSelector->SetAllowedExtensions("CHAR");
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString)) CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString));
return pSelector; return pSelector;
} }
@ -579,14 +581,14 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
pComboBox->addItem(TO_QSTRING(pAnimSet->getNodeName(iChr))); pComboBox->addItem(TO_QSTRING(pAnimSet->getNodeName(iChr)));
} }
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int)) CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int));
return pComboBox; return pComboBox;
} }
if (Type == eLongProperty) if (Type == eLongProperty)
{ {
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)) CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int));
return pSpinBox; return pSpinBox;
} }

View File

@ -35,6 +35,48 @@ IProperty* CPropertyModel::PropertyForIndex(const QModelIndex& rkIndex, bool Han
return static_cast<IProperty*>(rkIndex.internalPointer()); return static_cast<IProperty*>(rkIndex.internalPointer());
} }
QModelIndex CPropertyModel::IndexForProperty(IProperty *pProp) const
{
if (pProp == mpBaseStruct) return QModelIndex();
QVector<u32> RowNumbers;
IProperty *pChild = pProp;
CPropertyStruct *pParent = pProp->Parent();
while (pParent)
{
// Check for array with one sub-property
CPropertyStruct *pGrandparent = pParent->Parent();
if (pGrandparent && pGrandparent->Type() == eArrayProperty && pParent->Count() == 1)
{
pChild = pParent;
pParent = pGrandparent;
continue;
}
// Find row index for this child property
for (u32 iChild = 0; iChild < pParent->Count(); iChild++)
{
if (pParent->PropertyByIndex(iChild) == pChild)
{
RowNumbers << iChild;
break;
}
}
pChild = pParent;
pParent = pGrandparent;
}
// Find the corresponding QModelIndex in the same spot
QModelIndex Index = QModelIndex();
for (int iChild = RowNumbers.size() - 1; iChild >= 0; iChild--)
Index = index(RowNumbers[iChild], 0, Index);
return Index;
}
int CPropertyModel::columnCount(const QModelIndex& /*rkParent*/) const int CPropertyModel::columnCount(const QModelIndex& /*rkParent*/) const
{ {
return 2; return 2;
@ -393,6 +435,11 @@ Qt::ItemFlags CPropertyModel::flags(const QModelIndex& rkIndex) const
else return (Qt::ItemIsEnabled | Qt::ItemIsEditable); else return (Qt::ItemIsEnabled | Qt::ItemIsEditable);
} }
void CPropertyModel::NotifyPropertyModified(IProperty *pProp)
{
NotifyPropertyModified(IndexForProperty(pProp));
}
void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex) void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex)
{ {
if (rowCount(rkIndex) != 0) if (rowCount(rkIndex) != 0)
@ -405,7 +452,9 @@ void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex)
emit dataChanged(Parent, Parent); emit dataChanged(Parent, Parent);
} }
emit dataChanged(rkIndex, rkIndex); QModelIndex IndexC1 = rkIndex.sibling(rkIndex.row(), 1);
emit dataChanged(IndexC1, IndexC1);
emit PropertyModified(rkIndex); emit PropertyModified(rkIndex);
} }

View File

@ -14,6 +14,7 @@ public:
CPropertyModel(QObject *pParent = 0); CPropertyModel(QObject *pParent = 0);
void SetBaseStruct(CPropertyStruct *pBaseStruct); void SetBaseStruct(CPropertyStruct *pBaseStruct);
IProperty* PropertyForIndex(const QModelIndex& rkIndex, bool HandleFlaggedPointers) const; IProperty* PropertyForIndex(const QModelIndex& rkIndex, bool HandleFlaggedPointers) const;
QModelIndex IndexForProperty(IProperty *pProp) const;
int columnCount(const QModelIndex& rkParent) const; int columnCount(const QModelIndex& rkParent) const;
int rowCount(const QModelIndex& rkParent) const; int rowCount(const QModelIndex& rkParent) const;
@ -23,10 +24,14 @@ public:
QModelIndex parent(const QModelIndex& rkChild) const; QModelIndex parent(const QModelIndex& rkChild) const;
Qt::ItemFlags flags(const QModelIndex& rkIndex) const; Qt::ItemFlags flags(const QModelIndex& rkIndex) const;
void NotifyPropertyModified(const QModelIndex& rkIndex);
void ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize); void ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize);
void ArrayResized(const QModelIndex& rkIndex, u32 OldSize); void ArrayResized(const QModelIndex& rkIndex, u32 OldSize);
void ResizeArray(const QModelIndex& rkIndex, u32 NewSize); void ResizeArray(const QModelIndex& rkIndex, u32 NewSize);
public slots:
void NotifyPropertyModified(IProperty *pProp);
void NotifyPropertyModified(const QModelIndex& rkIndex);
signals: signals:
void PropertyModified(const QModelIndex& rkIndex); void PropertyModified(const QModelIndex& rkIndex);
}; };

View File

@ -17,7 +17,7 @@ CPropertyView::CPropertyView(QWidget *pParent)
connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(SetPersistentEditors(QModelIndex))); connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(SetPersistentEditors(QModelIndex)));
connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(edit(QModelIndex))); connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(edit(QModelIndex)));
connect(mpModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(SetPersistentEditors(QModelIndex))); connect(mpModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(SetPersistentEditors(QModelIndex)));
connect(mpModel, SIGNAL(PropertyModified(QModelIndex)), this, SLOT(OnPropertyModified(QModelIndex))); connect(mpModel, SIGNAL(PropertyModified(const QModelIndex&)), this, SLOT(OnPropertyModified(const QModelIndex&)));
} }
void CPropertyView::setModel(QAbstractItemModel *pModel) void CPropertyView::setModel(QAbstractItemModel *pModel)
@ -66,6 +66,7 @@ void CPropertyView::SetEditor(CWorldEditor *pEditor)
{ {
mpEditor = pEditor; mpEditor = pEditor;
mpDelegate->SetEditor(pEditor); mpDelegate->SetEditor(pEditor);
connect(mpEditor, SIGNAL(PropertyModified(IProperty*,bool)), mpModel, SLOT(NotifyPropertyModified(IProperty*)));
} }
void CPropertyView::SetInstance(CScriptObject *pObj) void CPropertyView::SetInstance(CScriptObject *pObj)
@ -83,7 +84,10 @@ void CPropertyView::SetInstance(CScriptObject *pObj)
void CPropertyView::UpdateEditorProperties(const QModelIndex& rkParent) void CPropertyView::UpdateEditorProperties(const QModelIndex& rkParent)
{ {
// Iterate over all properties and update if they're an editor property. Ignore structs unless they're EditorProperties or a single struct. // Check what game this is
EGame Game = mpEditor->ActiveArea()->Version();
// Iterate over all properties and update if they're an editor property.
for (int iRow = 0; iRow < mpModel->rowCount(rkParent); iRow++) for (int iRow = 0; iRow < mpModel->rowCount(rkParent); iRow++)
{ {
QModelIndex Index0 = mpModel->index(iRow, 0, rkParent); QModelIndex Index0 = mpModel->index(iRow, 0, rkParent);
@ -92,11 +96,15 @@ void CPropertyView::UpdateEditorProperties(const QModelIndex& rkParent)
if (pProp) if (pProp)
{ {
// For structs, update sub-properties.
if (pProp->Type() == eStructProperty) if (pProp->Type() == eStructProperty)
{ {
CStructTemplate *pStruct = static_cast<CStructTemplate*>(pProp->Template()); CStructTemplate *pStruct = static_cast<CStructTemplate*>(pProp->Template());
if (pStruct->IsSingleProperty() || pStruct->PropertyID() == 0x255A4580) // As an optimization, in MP2+, we don't need to update unless this is a single struct or if
// it's EditorProperties, because other structs never have editor properties in them.
// In MP1 this isn't the case so we need to update every struct regardless
if ((Game <= ePrime) || (pStruct->IsSingleProperty() || pStruct->PropertyID() == 0x255A4580))
UpdateEditorProperties(Index0); UpdateEditorProperties(Index0);
else else
continue; continue;
@ -180,16 +188,9 @@ void CPropertyView::OnPropertyModified(const QModelIndex& rkIndex)
// Check for a character resource being changed. If that's the case we need to remake the persistent editors. // Check for a character resource being changed. If that's the case we need to remake the persistent editors.
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, true); IProperty *pProp = mpModel->PropertyForIndex(rkIndex, true);
if (pProp->Type() == eCharacterProperty && rkIndex.internalId() & 0x1) if (pProp->Type() == eCharacterProperty /*&& rkIndex.internalId() & 0x1*/)
{ {
EGame Game = static_cast<TCharacterProperty*>(pProp)->Get().Version(); ClosePersistentEditors(rkIndex);
SetPersistentEditors(rkIndex);
if (mpDelegate->DetermineCharacterPropType(Game, rkIndex) == eFileProperty)
{
ClosePersistentEditors(rkIndex.parent());
SetPersistentEditors(rkIndex.parent());
} }
} }
emit PropertyModified(pProp);
}

View File

@ -29,9 +29,6 @@ public slots:
void SetPersistentEditors(const QModelIndex& rkIndex); void SetPersistentEditors(const QModelIndex& rkIndex);
void ClosePersistentEditors(const QModelIndex& rkIndex); void ClosePersistentEditors(const QModelIndex& rkIndex);
void OnPropertyModified(const QModelIndex& rkIndex); void OnPropertyModified(const QModelIndex& rkIndex);
signals:
void PropertyModified(IProperty *pProperty);
}; };
#endif // CPROPERTYVIEW_H #endif // CPROPERTYVIEW_H

View File

@ -1,16 +1,16 @@
#include "CBasicPropertyCommand.h" #include "CBasicPropertyCommand.h"
#include <Core/Resource/Script/IPropertyTemplate.h> #include <Core/Resource/Script/IPropertyTemplate.h>
CBasicPropertyCommand::CBasicPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex) CBasicPropertyCommand::CBasicPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, const QString& rkCommandName /*="Edit Property"*/)
: IUndoCommand("Edit Property") : IUndoCommand(rkCommandName)
, mpModel(pModel) , mpProperty(pProp)
, mpProperty(pModel->PropertyForIndex(rkIndex, true))
, mpTemplate(mpProperty->Template()) , mpTemplate(mpProperty->Template())
, mIndex(rkIndex) , mpBaseStruct(pProp->RootStruct())
, mpEditor(pEditor)
, mIsInArray(false) , mIsInArray(false)
{ {
// Check for array // Check for array
IProperty *pProp = mpProperty; IProperty *pChild = mpProperty;
IProperty *pParent = mpProperty->Parent(); IProperty *pParent = mpProperty->Parent();
while (pParent) while (pParent)
@ -24,31 +24,28 @@ CBasicPropertyCommand::CBasicPropertyCommand(CPropertyModel *pModel, const QMode
for (u32 iSub = 0; iSub < pArray->Count(); iSub++) for (u32 iSub = 0; iSub < pArray->Count(); iSub++)
{ {
if (pArray->PropertyByIndex(iSub) == pProp) if (pArray->PropertyByIndex(iSub) == pChild)
{ {
mArrayIndices << iSub; mArrayIndices << iSub;
break; break;
} }
} }
} }
pProp = pParent; pChild = pParent;
pParent = pParent->Parent(); pParent = pParent->Parent();
} }
} }
void CBasicPropertyCommand::UpdateArraySubProperty() void CBasicPropertyCommand::UpdateArraySubProperty()
{ {
// If an array has been sized down and then back up, then we might have an index to an invalid property. // If an array has been sized down and then back up, then we might have a pointer to an invalid property.
// Since we can't assume our index is still valid, we'll use the template and the model to find the corresponding property. // Since we can't assume our pointer is still valid, we'll use the template to find the corresponding property.
IPropertyTemplate *pTemp = mpTemplate; IPropertyTemplate *pTemp = mpTemplate;
CStructTemplate *pParent = mpTemplate->Parent(); CStructTemplate *pParent = mpTemplate->Parent();
QVector<u32> SubIndices; QVector<u32> SubIndices;
int IndexIndex = 0; int IndexIndex = 0;
if (mIndex.internalId() & 0x1)
SubIndices << mIndex.row();
while (pParent) while (pParent)
{ {
if (pParent->Type() != eArrayProperty || static_cast<CArrayTemplate*>(pParent)->Count() > 1) if (pParent->Type() != eArrayProperty || static_cast<CArrayTemplate*>(pParent)->Count() > 1)
@ -62,6 +59,8 @@ void CBasicPropertyCommand::UpdateArraySubProperty()
} }
} }
} }
else
SubIndices << 0;
if (pParent->Type() == eArrayProperty) if (pParent->Type() == eArrayProperty)
{ {
@ -73,15 +72,9 @@ void CBasicPropertyCommand::UpdateArraySubProperty()
pParent = pParent->Parent(); pParent = pParent->Parent();
} }
// Find corresponding index // Find corresponding property
QModelIndex Index = QModelIndex(); mpProperty = mpBaseStruct;
for (int iSub = SubIndices.size() - 1; iSub >= 0; iSub--) for (int iChild = SubIndices.size() - 1; iChild >= 0; iChild--)
Index = mpModel->index(SubIndices[iSub], 0, Index); mpProperty = static_cast<CPropertyStruct*>(mpProperty)->PropertyByIndex(SubIndices[iChild]);
Index = Index.sibling(Index.row(), 1);
// Get property
mpProperty = mpModel->PropertyForIndex(Index, true);
mIndex = Index;
} }

View File

@ -3,20 +3,21 @@
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "Editor/PropertyEdit/CPropertyModel.h" #include "Editor/PropertyEdit/CPropertyModel.h"
#include "Editor/WorldEditor/CWorldEditor.h"
class CBasicPropertyCommand : public IUndoCommand class CBasicPropertyCommand : public IUndoCommand
{ {
protected: protected:
CPropertyModel *mpModel;
IProperty *mpProperty; IProperty *mpProperty;
IPropertyTemplate *mpTemplate; IPropertyTemplate *mpTemplate;
QModelIndex mIndex; CPropertyStruct *mpBaseStruct;
CWorldEditor *mpEditor;
bool mIsInArray; bool mIsInArray;
QVector<u32> mArrayIndices; QVector<u32> mArrayIndices;
public: public:
CBasicPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex); CBasicPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, const QString& rkCommandName = "Edit Property");
virtual void UpdateArraySubProperty(); virtual void UpdateArraySubProperty();
virtual bool AffectsCleanState() const { return true; } virtual bool AffectsCleanState() const { return true; }
}; };

View File

@ -0,0 +1,42 @@
#include "CChangeLayerCommand.h"
CChangeLayerCommand::CChangeLayerCommand(CWorldEditor *pEditor, const QList<CScriptNode*>& rkNodeList, CScriptLayer *pNewLayer)
: IUndoCommand("Change Layer")
, mNodeList(rkNodeList)
, mpNewLayer(pNewLayer)
, mpEditor(pEditor)
{
foreach (CScriptNode *pNode, mNodeList)
{
CScriptLayer *pLayer = pNode->Object()->Layer();
if (pLayer == pNewLayer)
{
mNodeList.removeOne(pNode);
continue;
}
mOldLayers[pNode] = pLayer;
}
}
void CChangeLayerCommand::undo()
{
mpEditor->InstancesLayerAboutToChange();
foreach (CScriptNode *pNode, mNodeList)
pNode->Object()->SetLayer(mOldLayers[pNode]);
mpEditor->InstancesLayerChanged(mNodeList);
}
void CChangeLayerCommand::redo()
{
mpEditor->InstancesLayerAboutToChange();
foreach (CScriptNode *pNode, mNodeList)
pNode->Object()->SetLayer(mpNewLayer);
mpEditor->InstancesLayerChanged(mNodeList);
}

View File

@ -0,0 +1,22 @@
#ifndef CCHANGELAYERCOMMAND_H
#define CCHANGELAYERCOMMAND_H
#include "IUndoCommand.h"
#include "Editor/WorldEditor/CWorldEditor.h"
#include <Core/Scene/CScriptNode.h>
class CChangeLayerCommand : public IUndoCommand
{
QList<CScriptNode*> mNodeList;
QMap<CScriptNode*, CScriptLayer*> mOldLayers;
CScriptLayer *mpNewLayer;
CWorldEditor *mpEditor;
public:
CChangeLayerCommand(CWorldEditor *pEditor, const QList<CScriptNode*>& rkNodeList, CScriptLayer *pNewLayer);
void undo();
void redo();
bool AffectsCleanState() const { return true; }
};
#endif // CCHANGELAYERCOMMAND_H

View File

@ -1,8 +1,8 @@
#include "CEditScriptPropertyCommand.h" #include "CEditScriptPropertyCommand.h"
#include "EUndoCommand.h" #include "EUndoCommand.h"
CEditScriptPropertyCommand::CEditScriptPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, IPropertyValue *pOldValue, bool IsDone) CEditScriptPropertyCommand::CEditScriptPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, IPropertyValue *pOldValue, bool IsDone, const QString& rkCommandName /*= "Edit Property"*/)
: CBasicPropertyCommand(pModel, rkIndex) : CBasicPropertyCommand(pProp, pEditor, rkCommandName)
, mCommandEnded(IsDone) , mCommandEnded(IsDone)
{ {
mpOldValue = pOldValue; mpOldValue = pOldValue;
@ -41,12 +41,13 @@ void CEditScriptPropertyCommand::undo()
{ {
if (mIsInArray) UpdateArraySubProperty(); if (mIsInArray) UpdateArraySubProperty();
mpProperty->RawValue()->Copy(mpOldValue); mpProperty->RawValue()->Copy(mpOldValue);
mpModel->NotifyPropertyModified(mIndex); mpEditor->OnPropertyModified(mpProperty);
mCommandEnded = true;
} }
void CEditScriptPropertyCommand::redo() void CEditScriptPropertyCommand::redo()
{ {
if (mIsInArray) UpdateArraySubProperty(); if (mIsInArray) UpdateArraySubProperty();
mpProperty->RawValue()->Copy(mpNewValue); mpProperty->RawValue()->Copy(mpNewValue);
mpModel->NotifyPropertyModified(mIndex); mpEditor->OnPropertyModified(mpProperty);
} }

View File

@ -3,7 +3,6 @@
#include "CBasicPropertyCommand.h" #include "CBasicPropertyCommand.h"
#include "Editor/PropertyEdit/CPropertyModel.h" #include "Editor/PropertyEdit/CPropertyModel.h"
#include <QUndoCommand>
class CEditScriptPropertyCommand : public CBasicPropertyCommand class CEditScriptPropertyCommand : public CBasicPropertyCommand
{ {
@ -12,7 +11,7 @@ class CEditScriptPropertyCommand : public CBasicPropertyCommand
bool mCommandEnded; bool mCommandEnded;
public: public:
CEditScriptPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, IPropertyValue *pOldValue, bool IsDone); CEditScriptPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, IPropertyValue *pOldValue, bool IsDone, const QString& rkCommandName = "Edit Property");
~CEditScriptPropertyCommand(); ~CEditScriptPropertyCommand();
int id() const; int id() const;
bool mergeWith(const QUndoCommand *pkOther); bool mergeWith(const QUndoCommand *pkOther);

View File

@ -1,8 +1,9 @@
#include "CResizeScriptArrayCommand.h" #include "CResizeScriptArrayCommand.h"
CResizeScriptArrayCommand::CResizeScriptArrayCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, u32 NewSize) CResizeScriptArrayCommand::CResizeScriptArrayCommand(IProperty *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize)
: CBasicPropertyCommand(pModel, rkIndex) : CBasicPropertyCommand(pProp, pEditor)
, mpArray(static_cast<CArrayProperty*>(mpProperty)) , mpArray(static_cast<CArrayProperty*>(mpProperty))
, mpModel(pModel)
, mOldSize(mpArray->Count()) , mOldSize(mpArray->Count())
, mNewSize(NewSize) , mNewSize(NewSize)
{ {
@ -10,7 +11,7 @@ CResizeScriptArrayCommand::CResizeScriptArrayCommand(CPropertyModel *pModel, con
if (!mNewSizeLarger) if (!mNewSizeLarger)
{ {
for (u32 iSub = mNewSize; iSub < mOldSize; iSub++) for (int iSub = mNewSize; iSub < mOldSize; iSub++)
{ {
mDeletedProperties << mpArray->PropertyByIndex(iSub)->Clone(); mDeletedProperties << mpArray->PropertyByIndex(iSub)->Clone();
} }
@ -29,21 +30,22 @@ void CResizeScriptArrayCommand::undo()
{ {
if (mIsInArray) UpdateArraySubProperty(); if (mIsInArray) UpdateArraySubProperty();
mpModel->ArrayAboutToBeResized(mIndex, mOldSize); QModelIndex Index = mpModel->IndexForProperty(mpProperty);
mpModel->ArrayAboutToBeResized(Index, (u32) mOldSize);
mpArray->Resize(mOldSize); mpArray->Resize(mOldSize);
if (!mNewSizeLarger) if (!mNewSizeLarger)
{ {
u32 NumNewElements = mOldSize - mNewSize; int NumNewElements = mOldSize - mNewSize;
for (u32 iSub = 0; iSub < NumNewElements; iSub++) for (int iSub = 0; iSub < NumNewElements; iSub++)
{ {
u32 Idx = iSub + mNewSize; u32 Idx = iSub + mNewSize;
mpArray->PropertyByIndex(Idx)->Copy(mDeletedProperties[iSub]); mpArray->PropertyByIndex(Idx)->Copy(mDeletedProperties[iSub]);
} }
} }
mpModel->ArrayResized(mIndex, mNewSize); mpModel->ArrayResized(Index, (u32) mNewSize);
} }
} }
@ -54,9 +56,10 @@ void CResizeScriptArrayCommand::redo()
{ {
if (mIsInArray) UpdateArraySubProperty(); if (mIsInArray) UpdateArraySubProperty();
mpModel->ArrayAboutToBeResized(mIndex, mNewSize); QModelIndex Index = mpModel->IndexForProperty(mpProperty);
mpModel->ArrayAboutToBeResized(Index, (u32) mNewSize);
mpArray->Resize(mNewSize); mpArray->Resize(mNewSize);
mpModel->ArrayResized(mIndex, mOldSize); mpModel->ArrayResized(Index, (u32) mOldSize);
} }
} }

View File

@ -9,13 +9,14 @@ class CResizeScriptArrayCommand : public CBasicPropertyCommand
{ {
CArrayProperty *mpArray; CArrayProperty *mpArray;
QVector<IProperty*> mDeletedProperties; QVector<IProperty*> mDeletedProperties;
CPropertyModel *mpModel;
u32 mOldSize; int mOldSize;
u32 mNewSize; int mNewSize;
bool mNewSizeLarger; bool mNewSizeLarger;
public: public:
CResizeScriptArrayCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, u32 NewSize); CResizeScriptArrayCommand(IProperty *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize);
~CResizeScriptArrayCommand(); ~CResizeScriptArrayCommand();
void undo(); void undo();
void redo(); void redo();

View File

@ -1,6 +1,8 @@
#ifndef EUNDOCOMMAND #ifndef EUNDOCOMMAND
#define EUNDOCOMMAND #define EUNDOCOMMAND
// This enum is used as an ID for merging undo commands.
// If a command can't merge, then it doesn't have to be listed here.
enum EUndoCommand enum EUndoCommand
{ {
eTranslateNodeCmd, eTranslateNodeCmd,

View File

@ -4,13 +4,17 @@
#include "CTranslateNodeCommand.h" #include "CTranslateNodeCommand.h"
#include "CRotateNodeCommand.h" #include "CRotateNodeCommand.h"
#include "CScaleNodeCommand.h" #include "CScaleNodeCommand.h"
#include "CSelectNodeCommand.h" #include "CSelectNodeCommand.h"
#include "CDeselectNodeCommand.h" #include "CDeselectNodeCommand.h"
#include "CClearSelectionCommand.h" #include "CClearSelectionCommand.h"
#include "CSelectAllCommand.h" #include "CSelectAllCommand.h"
#include "CInvertSelectionCommand.h" #include "CInvertSelectionCommand.h"
#include "CEditScriptPropertyCommand.h" #include "CEditScriptPropertyCommand.h"
#include "CResizeScriptArrayCommand.h" #include "CResizeScriptArrayCommand.h"
#include "CChangeLayerCommand.h"
#include "EUndoCommand.h" #include "EUndoCommand.h"
#endif // UNDOCOMMANDS #endif // UNDOCOMMANDS

View File

@ -5,7 +5,8 @@
#include <QApplication> #include <QApplication>
#include <QIcon> #include <QIcon>
/* The tree has 3 levels: /*
* The tree has 3 levels:
* 1. Node Type (Script Object, Light, World Mesh, etc) - represented with ID of 0 * 1. Node Type (Script Object, Light, World Mesh, etc) - represented with ID of 0
* 2. Object Type (Actor, Platform, SpawnPoint, etc) - represented with flags * 2. Object Type (Actor, Platform, SpawnPoint, etc) - represented with flags
* 3. Instance - represented with pointer to instance (0x1 bit is guaranteed to be clear) * 3. Instance - represented with pointer to instance (0x1 bit is guaranteed to be clear)
@ -15,6 +16,8 @@
* A: Row index * A: Row index
* B: Node type row index * B: Node type row index
* C: Item type (ObjType, Instance) * C: Item type (ObjType, Instance)
*
* Also this class is kind of a mess, it would be nice to rewrite it at some point
*/ */
#define TYPES_ROW_INDEX_MASK 0xFFFFFFE0 #define TYPES_ROW_INDEX_MASK 0xFFFFFFE0
#define TYPES_NODE_TYPE_MASK 0x0000001E #define TYPES_NODE_TYPE_MASK 0x0000001E
@ -87,7 +90,7 @@ QModelIndex CInstancesModel::index(int row, int column, const QModelIndex &paren
if (mModelType == eLayers) if (mModelType == eLayers)
{ {
CScriptLayer *pLayer = mpArea->GetScriptLayer(parent.row()); CScriptLayer *pLayer = mpArea->GetScriptLayer(parent.row());
if ((u32) row >= pLayer->GetNumObjects()) if ((u32) row >= pLayer->NumInstances())
return QModelIndex(); return QModelIndex();
else else
return createIndex(row, column, (*pLayer)[row]); return createIndex(row, column, (*pLayer)[row]);
@ -185,7 +188,7 @@ int CInstancesModel::rowCount(const QModelIndex &parent) const
{ {
u32 RowIndex = ((parent.internalId() & TYPES_ROW_INDEX_MASK) >> TYPES_ROW_INDEX_SHIFT); u32 RowIndex = ((parent.internalId() & TYPES_ROW_INDEX_MASK) >> TYPES_ROW_INDEX_SHIFT);
if (mModelType == eLayers) if (mModelType == eLayers)
return (mpArea ? mpArea->GetScriptLayer(RowIndex)->GetNumObjects() : 0); return (mpArea ? mpArea->GetScriptLayer(RowIndex)->NumInstances() : 0);
else else
return mTemplateList[RowIndex]->NumObjects(); return mTemplateList[RowIndex]->NumObjects();
} }
@ -310,8 +313,13 @@ QVariant CInstancesModel::data(const QModelIndex &index, int role) const
void CInstancesModel::SetEditor(CWorldEditor *pEditor) void CInstancesModel::SetEditor(CWorldEditor *pEditor)
{ {
if (mpEditor)
disconnect(mpEditor, 0, this, 0);
mpEditor = pEditor; mpEditor = pEditor;
mpScene = (pEditor ? pEditor->Scene() : nullptr); mpScene = (pEditor ? pEditor->Scene() : nullptr);
connect(mpEditor, SIGNAL(InstancesLayerAboutToChange()), this, SLOT(InstancesLayerPreChange()));
connect(mpEditor, SIGNAL(InstancesLayerChanged(QList<CScriptNode*>)), this, SLOT(InstancesLayerPostChange(QList<CScriptNode*>)));
} }
void CInstancesModel::SetMaster(CMasterTemplate *pMaster) void CInstancesModel::SetMaster(CMasterTemplate *pMaster)
@ -404,6 +412,46 @@ CScriptObject* CInstancesModel::IndexObject(const QModelIndex& index) const
return static_cast<CScriptObject*>(index.internalPointer()); return static_cast<CScriptObject*>(index.internalPointer());
} }
// ************ PUBLIC SLOTS ************
void CInstancesModel::InstancesLayerPreChange()
{
// This is only really needed on layers, which have rows moved.
// Types just need to update column 1 so we can handle that when the change is finished.
if (mModelType == eLayers)
emit layoutAboutToBeChanged();
}
void CInstancesModel::InstancesLayerPostChange(const QList<CScriptNode*>& rkInstanceList)
{
QList<CScriptObject*> InstanceList;
foreach (CScriptNode *pNode, rkInstanceList)
InstanceList << pNode->Object();
QModelIndex ScriptIdx = index(0, 0, QModelIndex());
// For types, just find the instances that have changed layers and emit dataChanged for column 1.
if (mModelType == eTypes)
{
for (int iType = 0; iType < rowCount(ScriptIdx); iType++)
{
QModelIndex TypeIdx = index(iType, 0, ScriptIdx);
for (int iInst = 0; iInst < rowCount(TypeIdx); iInst++)
{
QModelIndex InstIdx = index(iInst, 1, TypeIdx);
CScriptObject *pInst = IndexObject(InstIdx);
if (InstanceList.contains(pInst))
emit dataChanged(InstIdx, InstIdx);
}
}
}
// For layers we just need to emit layoutChanged() and done
else
emit layoutChanged();
}
// ************ STATIC ************ // ************ STATIC ************
CInstancesModel::EIndexType CInstancesModel::IndexType(const QModelIndex& index) CInstancesModel::EIndexType CInstancesModel::IndexType(const QModelIndex& index)
{ {

View File

@ -56,6 +56,10 @@ public:
CScriptTemplate* IndexTemplate(const QModelIndex& index) const; CScriptTemplate* IndexTemplate(const QModelIndex& index) const;
CScriptObject* IndexObject(const QModelIndex& index) const; CScriptObject* IndexObject(const QModelIndex& index) const;
public slots:
void InstancesLayerPreChange();
void InstancesLayerPostChange(const QList<CScriptNode*>& rkInstanceList);
// Static // Static
static EIndexType IndexType(const QModelIndex& index); static EIndexType IndexType(const QModelIndex& index);
static ENodeType IndexNodeType(const QModelIndex& index); static ENodeType IndexNodeType(const QModelIndex& index);

View File

@ -5,6 +5,7 @@
#include "WInstancesTab.h" #include "WInstancesTab.h"
#include "Editor/CBasicViewport.h" #include "Editor/CBasicViewport.h"
#include "Editor/PropertyEdit/CPropertyView.h"
#include "Editor/Widgets/WDraggableSpinBox.h" #include "Editor/Widgets/WDraggableSpinBox.h"
#include "Editor/Widgets/WVectorEditor.h" #include "Editor/Widgets/WVectorEditor.h"
#include "Editor/Undo/UndoCommands.h" #include "Editor/Undo/UndoCommands.h"
@ -80,6 +81,12 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
connect(&mUndoStack, SIGNAL(indexChanged(int)), this, SLOT(OnUndoStackIndexChanged())); connect(&mUndoStack, SIGNAL(indexChanged(int)), this, SLOT(OnUndoStackIndexChanged()));
connect(ui->ActionSave, SIGNAL(triggered()), this, SLOT(Save())); connect(ui->ActionSave, SIGNAL(triggered()), this, SLOT(Save()));
ui->CreateTabEditorProperties->SyncToEditor(this);
ui->ModifyTabEditorProperties->SyncToEditor(this);
ui->InstancesTabEditorProperties->SyncToEditor(this);
ui->DisplayTabEditorProperties->SyncToEditor(this);
ui->WorldTabEditorProperties->SyncToEditor(this);
} }
CWorldEditor::~CWorldEditor() CWorldEditor::~CWorldEditor()
@ -172,6 +179,8 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea, u32 AreaIndex)
CStringTable *pWorldNameTable = mpWorld->GetWorldName(); CStringTable *pWorldNameTable = mpWorld->GetWorldName();
TWideString WorldName = pWorldNameTable ? pWorldNameTable->GetString("ENGL", 0) : "[Untitled World]"; TWideString WorldName = pWorldNameTable ? pWorldNameTable->GetString("ENGL", 0) : "[Untitled World]";
if (CurrentGame() < eReturns)
{
CStringTable *pAreaNameTable = mpWorld->GetAreaName(AreaIndex); CStringTable *pAreaNameTable = mpWorld->GetAreaName(AreaIndex);
TWideString AreaName = pAreaNameTable ? pAreaNameTable->GetString("ENGL", 0) : (TWideString("!") + mpWorld->GetAreaInternalName(AreaIndex).ToUTF16()); TWideString AreaName = pAreaNameTable ? pAreaNameTable->GetString("ENGL", 0) : (TWideString("!") + mpWorld->GetAreaInternalName(AreaIndex).ToUTF16());
@ -181,9 +190,13 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea, u32 AreaIndex)
setWindowTitle(QString("Prime World Editor - %1 - %2[*]").arg(TO_QSTRING(WorldName)).arg(TO_QSTRING(AreaName))); setWindowTitle(QString("Prime World Editor - %1 - %2[*]").arg(TO_QSTRING(WorldName)).arg(TO_QSTRING(AreaName)));
} }
CGameArea* CWorldEditor::ActiveArea() else
{ {
return mpArea; setWindowTitle(QString("Prime World Editor - %1[*]").arg(TO_QSTRING(WorldName)));
}
// Emit signals
emit LayersModified();
} }
bool CWorldEditor::CheckUnsavedChanges() bool CWorldEditor::CheckUnsavedChanges()
@ -228,6 +241,110 @@ bool CWorldEditor::Save()
} }
} }
void CWorldEditor::OnPropertyModified(IProperty *pProp)
{
bool EditorProperty = false;
if (!mSelection.isEmpty() && mSelection.front()->NodeType() == eScriptNode)
{
CScriptNode *pScript = static_cast<CScriptNode*>(mSelection.front());
pScript->PropertyModified(pProp);
// Check editor property
if (pScript->Object()->IsEditorProperty(pProp))
EditorProperty = true;
// If this is an editor property, update other parts of the UI to reflect the new value.
if (EditorProperty)
{
UpdateStatusBar();
UpdateSelectionUI();
}
// If this is a model/character, then we'll treat this as a modified selection. This is to make sure the selection bounds updates.
if (pProp->Type() == eFileProperty)
{
CFileTemplate *pFile = static_cast<CFileTemplate*>(pProp->Template());
if (pFile->AcceptsExtension("CMDL") || pFile->AcceptsExtension("ANCS") || pFile->AcceptsExtension("CHAR"))
NotifySelectionModified();
}
else if (pProp->Type() == eCharacterProperty)
NotifySelectionModified();
// Emit signal so other widgets can react to the property change
emit PropertyModified(pProp, EditorProperty);
}
}
void CWorldEditor::SetSelectionActive(bool Active)
{
// Gather list of selected objects that actually have Active properties
QVector<CScriptObject*> Objects;
foreach (CSceneNode *pNode, mSelection)
{
if (pNode->NodeType() == eScriptNode)
{
CScriptNode *pScript = static_cast<CScriptNode*>(pNode);
CScriptObject *pInst = pScript->Object();
IProperty *pActive = pInst->ActiveProperty();
if (pActive)
Objects << pInst;
}
}
if (!Objects.isEmpty())
{
mUndoStack.beginMacro("Toggle Active");
foreach (CScriptObject *pInst, Objects)
{
IProperty *pActive = pInst->ActiveProperty();
IPropertyValue *pOld = pActive->RawValue()->Clone();
pInst->SetActive(Active);
mUndoStack.push(new CEditScriptPropertyCommand(pActive, this, pOld, true));
}
mUndoStack.endMacro();
}
}
void CWorldEditor::SetSelectionInstanceNames(const QString& rkNewName, bool IsDone)
{
// todo: this only supports one node at a time because a macro prevents us from merging undo commands
// this is fine right now because this function is only ever called with a selection of one node, but probably want to fix in the future
if (mSelection.size() == 1 && mSelection.front()->NodeType() == eScriptNode)
{
CScriptNode *pNode = static_cast<CScriptNode*>(mSelection.front());
CScriptObject *pInst = pNode->Object();
IProperty *pName = pInst->InstanceNameProperty();
if (pName)
{
TString NewName = TO_TSTRING(rkNewName);
IPropertyValue *pOld = pName->RawValue()->Clone();
pInst->SetName(NewName);
mUndoStack.push(new CEditScriptPropertyCommand(pName, this, pOld, IsDone, "Edit Instance Name"));
}
}
}
void CWorldEditor::SetSelectionLayer(CScriptLayer *pLayer)
{
QList<CScriptNode*> ScriptNodes;
foreach (CSceneNode *pNode, mSelection)
{
if (pNode->NodeType() == eScriptNode)
ScriptNodes << static_cast<CScriptNode*>(pNode);
}
if (!ScriptNodes.isEmpty())
mUndoStack.push(new CChangeLayerCommand(this, ScriptNodes, pLayer));
}
void CWorldEditor::UpdateStatusBar() void CWorldEditor::UpdateStatusBar()
{ {
// Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag. // Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag.
@ -368,7 +485,13 @@ void CWorldEditor::OnUndoStackIndexChanged()
{ {
const QUndoCommand *pkQCmd = mUndoStack.command(iIdx); const QUndoCommand *pkQCmd = mUndoStack.command(iIdx);
if (pkQCmd->childCount() > 0) if (const IUndoCommand *pkCmd = dynamic_cast<const IUndoCommand*>(pkQCmd))
{
if (pkCmd->AffectsCleanState())
IsClean = false;
}
else if (pkQCmd->childCount() > 0)
{ {
for (int iChild = 0; iChild < pkQCmd->childCount(); iChild++) for (int iChild = 0; iChild < pkQCmd->childCount(); iChild++)
{ {
@ -382,14 +505,6 @@ void CWorldEditor::OnUndoStackIndexChanged()
} }
} }
else
{
const IUndoCommand *pkCmd = static_cast<const IUndoCommand*>(pkQCmd);
if (pkCmd->AffectsCleanState())
IsClean = false;
}
if (!IsClean) break; if (!IsClean) break;
} }

View File

@ -43,11 +43,17 @@ public:
void closeEvent(QCloseEvent *pEvent); void closeEvent(QCloseEvent *pEvent);
bool eventFilter(QObject *pObj, QEvent *pEvent); bool eventFilter(QObject *pObj, QEvent *pEvent);
void SetArea(CWorld *pWorld, CGameArea *pArea, u32 AreaIndex); void SetArea(CWorld *pWorld, CGameArea *pArea, u32 AreaIndex);
CGameArea* ActiveArea();
bool CheckUnsavedChanges(); bool CheckUnsavedChanges();
inline CGameArea* ActiveArea() const { return mpArea; }
inline EGame CurrentGame() const { return mpArea->Version(); }
public slots: public slots:
bool Save(); bool Save();
void OnPropertyModified(IProperty *pProp);
void SetSelectionActive(bool Active);
void SetSelectionInstanceNames(const QString& rkNewName, bool IsDone);
void SetSelectionLayer(CScriptLayer *pLayer);
void UpdateStatusBar(); void UpdateStatusBar();
void UpdateGizmoUI(); void UpdateGizmoUI();
@ -89,6 +95,12 @@ private slots:
void on_ActionSelectAll_triggered(); void on_ActionSelectAll_triggered();
void on_ActionInvertSelection_triggered(); void on_ActionInvertSelection_triggered();
void on_ActionEditPoiToWorldMap_triggered(); void on_ActionEditPoiToWorldMap_triggered();
signals:
void LayersModified();
void InstancesLayerAboutToChange();
void InstancesLayerChanged(const QList<CScriptNode*>& rkInstanceList);
void PropertyModified(IProperty *pProp, bool IsEditorProperty);
}; };
#endif // CWORLDEDITOR_H #endif // CWORLDEDITOR_H

View File

@ -20,7 +20,7 @@
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<widget class="QWidget" name=""> <widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
<item> <item>
<widget class="CSceneViewport" name="MainViewport" native="true"> <widget class="CSceneViewport" name="MainViewport" native="true">
@ -251,19 +251,7 @@
<attribute name="toolTip"> <attribute name="toolTip">
<string>Create</string> <string>Create</string>
</attribute> </attribute>
</widget> <layout class="QVBoxLayout" name="verticalLayout_2">
<widget class="QWidget" name="ModifyTab">
<attribute name="icon">
<iconset resource="../Icons.qrc">
<normaloff>:/icons/Modify.png</normaloff>:/icons/Modify.png</iconset>
</attribute>
<attribute name="title">
<string/>
</attribute>
<attribute name="toolTip">
<string>Modify</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@ -277,7 +265,62 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="WModifyTab" name="ModifyTabContents" native="true"/> <widget class="WEditorProperties" name="CreateTabEditorProperties" native="true"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="ModifyTab">
<attribute name="icon">
<iconset resource="../Icons.qrc">
<normaloff>:/icons/Modify.png</normaloff>:/icons/Modify.png</iconset>
</attribute>
<attribute name="title">
<string/>
</attribute>
<attribute name="toolTip">
<string>Modify</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="WEditorProperties" name="ModifyTabEditorProperties" native="true"/>
</item>
<item>
<widget class="WModifyTab" name="ModifyTabContents" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -292,7 +335,7 @@
<attribute name="toolTip"> <attribute name="toolTip">
<string>Instances</string> <string>Instances</string>
</attribute> </attribute>
<layout class="QHBoxLayout" name="InstancesTabLayout"> <layout class="QVBoxLayout" name="verticalLayout_6">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@ -306,7 +349,24 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="WInstancesTab" name="InstancesTabContents" native="true"/> <widget class="WEditorProperties" name="InstancesTabEditorProperties" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="WInstancesTab" name="InstancesTabContents" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -321,6 +381,36 @@
<attribute name="toolTip"> <attribute name="toolTip">
<string>Display</string> <string>Display</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="WEditorProperties" name="DisplayTabEditorProperties" native="true"/>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget> </widget>
<widget class="QWidget" name="WorldTab"> <widget class="QWidget" name="WorldTab">
<attribute name="icon"> <attribute name="icon">
@ -333,6 +423,36 @@
<attribute name="toolTip"> <attribute name="toolTip">
<string>World</string> <string>World</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_8">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="WEditorProperties" name="WorldTabEditorProperties" native="true"/>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget> </widget>
</widget> </widget>
</widget> </widget>
@ -771,6 +891,12 @@
<header>Editor/CSceneViewport.h</header> <header>Editor/CSceneViewport.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>WEditorProperties</class>
<extends>QWidget</extends>
<header>Editor/WorldEditor/WEditorProperties.h</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="../Icons.qrc"/> <include location="../Icons.qrc"/>

View File

@ -0,0 +1,196 @@
#include "WEditorProperties.h"
#include "Editor/Undo/CEditScriptPropertyCommand.h"
#include <Core/Resource/Script/CScriptLayer.h>
WEditorProperties::WEditorProperties(QWidget *pParent /*= 0*/)
: QWidget(pParent)
, mpEditor(nullptr)
, mpDisplayNode(nullptr)
, mHasEditedName(false)
{
mpActiveCheckBox = new QCheckBox;
mpActiveCheckBox->setToolTip("Active");
mpInstanceNameLineEdit = new QLineEdit;
mpInstanceNameLineEdit->setToolTip("Instance Name");
mpNameLayout = new QHBoxLayout;
mpNameLayout->addWidget(mpActiveCheckBox);
mpNameLayout->addWidget(mpInstanceNameLineEdit);
mpLayersLabel = new QLabel;
mpLayersLabel->setText("Layer:");
mpLayersLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
mpLayersComboBox = new QComboBox;
mpLayersComboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
mpLayersLayout = new QHBoxLayout;
mpLayersLayout->addWidget(mpLayersLabel);
mpLayersLayout->addWidget(mpLayersComboBox);
mpMainLayout = new QVBoxLayout;
mpMainLayout->addLayout(mpNameLayout);
mpMainLayout->addLayout(mpLayersLayout);
mpMainLayout->setContentsMargins(6, 6, 6, 0);
mpMainLayout->setSpacing(3);
setLayout(mpMainLayout);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
QFont Font = font();
Font.setPointSize(10);
setFont(Font);
mpInstanceNameLineEdit->setFont(Font);
mpLayersLabel->setFont(Font);
QFont ComboFont = mpLayersComboBox->font();
ComboFont.setPointSize(10);
mpLayersComboBox->setFont(ComboFont);
connect(mpActiveCheckBox, SIGNAL(clicked()), this, SLOT(OnActiveChanged()));
connect(mpInstanceNameLineEdit, SIGNAL(textEdited(QString)), this, SLOT(OnInstanceNameEdited()));
connect(mpInstanceNameLineEdit, SIGNAL(editingFinished()), this, SLOT(OnInstanceNameEditFinished()));
connect(mpLayersComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnLayerChanged()));
}
void WEditorProperties::SyncToEditor(CWorldEditor *pEditor)
{
if (mpEditor)
disconnect(mpEditor, 0, this, 0);
mpEditor = pEditor;
connect(mpEditor, SIGNAL(SelectionModified()), this, SLOT(OnSelectionModified()));
connect(mpEditor, SIGNAL(LayersModified()), this, SLOT(OnLayersModified()));
connect(mpEditor, SIGNAL(InstancesLayerChanged(QList<CScriptNode*>)), this, SLOT(OnInstancesLayerChanged(QList<CScriptNode*>)));
connect(mpEditor, SIGNAL(PropertyModified(IProperty*,bool)), this, SLOT(OnPropertyModified(IProperty*,bool)));
OnLayersModified();
}
void WEditorProperties::SetLayerComboBox()
{
mpLayersComboBox->blockSignals(true);
if (mpDisplayNode && mpDisplayNode->NodeType() == eScriptNode)
{
CScriptNode *pScript = static_cast<CScriptNode*>(mpDisplayNode);
CScriptLayer *pLayer = pScript->Object()->Layer();
for (u32 iLyr = 0; iLyr < mpEditor->ActiveArea()->GetScriptLayerCount(); iLyr++)
{
if (mpEditor->ActiveArea()->GetScriptLayer(iLyr) == pLayer)
{
mpLayersComboBox->setCurrentIndex(iLyr);
break;
}
}
mpLayersComboBox->setEnabled(true);
}
else
{
mpLayersComboBox->setCurrentIndex(-1);
mpLayersComboBox->setEnabled(false);
}
mpLayersComboBox->blockSignals(false);
}
// ************ PUBLIC SLOTS ************
void WEditorProperties::OnSelectionModified()
{
const QList<CSceneNode*>& rkSelection = mpEditor->GetSelection();
mpDisplayNode = (rkSelection.size() == 1 ? rkSelection.front() : nullptr);
if (rkSelection.empty() || rkSelection.size() != 1 || mpDisplayNode->NodeType() != eScriptNode)
{
mpActiveCheckBox->setChecked(false);
mpActiveCheckBox->setEnabled(false);
mpInstanceNameLineEdit->setEnabled(false);
if (rkSelection.empty())
mpInstanceNameLineEdit->clear();
else if (mpDisplayNode)
mpInstanceNameLineEdit->setText(TO_QSTRING(mpDisplayNode->Name()));
else
mpInstanceNameLineEdit->setText(QString("[%1 objects selected]").arg(rkSelection.size()));
}
else
{
UpdatePropertyValues();
}
SetLayerComboBox();
}
void WEditorProperties::OnPropertyModified(IProperty* /*pProp*/, bool IsEditorProperty)
{
if (!mpInstanceNameLineEdit->hasFocus())
{
if (mpDisplayNode->NodeType() == eScriptNode && IsEditorProperty)
UpdatePropertyValues();
}
}
void WEditorProperties::OnInstancesLayerChanged(const QList<CScriptNode*>& rkNodeList)
{
if (rkNodeList.contains((CScriptNode*) mpDisplayNode))
SetLayerComboBox();
}
void WEditorProperties::OnLayersModified()
{
CGameArea *pArea = mpEditor->ActiveArea();
mpLayersComboBox->clear();
if (pArea)
{
for (u32 iLyr = 0; iLyr < pArea->GetScriptLayerCount(); iLyr++)
mpLayersComboBox->addItem(TO_QSTRING(pArea->GetScriptLayer(iLyr)->Name()));
}
SetLayerComboBox();
}
void WEditorProperties::UpdatePropertyValues()
{
CScriptNode *pScript = static_cast<CScriptNode*>(mpDisplayNode);
CScriptObject *pInst = pScript->Object();
mpActiveCheckBox->setChecked(pInst->IsActive());
mpActiveCheckBox->setEnabled(pInst->ActiveProperty() != nullptr);
mpInstanceNameLineEdit->blockSignals(true);
mpInstanceNameLineEdit->setText(TO_QSTRING(pInst->InstanceName()));
mpInstanceNameLineEdit->setEnabled(pInst->InstanceNameProperty() != nullptr);
mpInstanceNameLineEdit->blockSignals(false);
}
// ************ PROTECTED SLOTS ************
void WEditorProperties::OnActiveChanged()
{
mpEditor->SetSelectionActive(mpActiveCheckBox->isChecked());
}
void WEditorProperties::OnInstanceNameEdited()
{
// This function triggers when the user is actively editing the Instance Name line edit.
mHasEditedName = true;
mpEditor->SetSelectionInstanceNames(mpInstanceNameLineEdit->text(), false);
}
void WEditorProperties::OnInstanceNameEditFinished()
{
// This function triggers when the user is finished editing the Instance Name line edit.
if (mHasEditedName)
mpEditor->SetSelectionInstanceNames(mpInstanceNameLineEdit->text(), true);
mHasEditedName = false;
}
void WEditorProperties::OnLayerChanged()
{
int Index = mpLayersComboBox->currentIndex();
if (Index >= 0)
{
CScriptLayer *pLayer = mpEditor->ActiveArea()->GetScriptLayer(Index);
mpEditor->SetSelectionLayer(pLayer);
}
}

View File

@ -0,0 +1,51 @@
#ifndef WEDITORPROPERTIES_H
#define WEDITORPROPERTIES_H
#include <QWidget>
#include "CWorldEditor.h"
#include <QCheckBox>
#include <QComboBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QVBoxLayout>
class WEditorProperties : public QWidget
{
Q_OBJECT
CWorldEditor *mpEditor;
CSceneNode *mpDisplayNode;
QVBoxLayout *mpMainLayout;
QCheckBox *mpActiveCheckBox;
QLineEdit *mpInstanceNameLineEdit;
QHBoxLayout *mpNameLayout;
QLabel *mpLayersLabel;
QComboBox *mpLayersComboBox;
QHBoxLayout *mpLayersLayout;
bool mHasEditedName;
public:
WEditorProperties(QWidget *pParent = 0);
void SyncToEditor(CWorldEditor *pEditor);
void SetLayerComboBox();
public slots:
void OnSelectionModified();
void OnPropertyModified(IProperty *pProp, bool IsEditorProperty);
void OnInstancesLayerChanged(const QList<CScriptNode*>& rkNodeList);
void OnLayersModified();
void UpdatePropertyValues();
protected slots:
void OnActiveChanged();
void OnInstanceNameEdited();
void OnInstanceNameEditFinished();
void OnLayerChanged();
};
#endif // WEDITORPROPERTIES_H

View File

@ -16,7 +16,6 @@ WModifyTab::WModifyTab(QWidget *pParent) :
ui->PropertyView->header()->resizeSection(0, PropViewWidth * 0.3); ui->PropertyView->header()->resizeSection(0, PropViewWidth * 0.3);
ui->PropertyView->header()->resizeSection(1, PropViewWidth * 0.3); ui->PropertyView->header()->resizeSection(1, PropViewWidth * 0.3);
ui->PropertyView->header()->setSectionResizeMode(1, QHeaderView::Fixed); ui->PropertyView->header()->setSectionResizeMode(1, QHeaderView::Fixed);
connect(ui->PropertyView, SIGNAL(PropertyModified(IProperty*)), this, SLOT(OnPropertyModified(IProperty*)));
mpInLinkModel = new CLinkModel(this); mpInLinkModel = new CLinkModel(this);
mpInLinkModel->SetConnectionType(CLinkModel::eIncoming); mpInLinkModel->SetConnectionType(CLinkModel::eIncoming);
@ -86,30 +85,7 @@ void WModifyTab::OnWorldSelectionTransformed()
ui->PropertyView->UpdateEditorProperties(QModelIndex()); ui->PropertyView->UpdateEditorProperties(QModelIndex());
} }
void WModifyTab::OnPropertyModified(IProperty *pProp) // ************ PRIVATE SLOTS ************
{
if (mpSelectedNode->NodeType() == eScriptNode)
{
CScriptNode *pNode = static_cast<CScriptNode*>(mpSelectedNode);
pNode->PropertyModified(pProp);
// If this is the instance name property, then other parts of the UI need to be updated to reflect the new name.
if (pNode->Object()->IsEditorProperty(pProp) && pProp->Type() == eStringProperty)
mpWorldEditor->UpdateSelectionUI();
// If this is a model/character, then we'll treat it as a modified selection. This is to make sure the selection bounds updates.
if (pProp->Type() == eFileProperty)
{
CFileTemplate *pFile = static_cast<CFileTemplate*>(pProp->Template());
if (pFile->AcceptsExtension("CMDL") || pFile->AcceptsExtension("ANCS") || pFile->AcceptsExtension("CHAR"))
mpWorldEditor->NotifySelectionModified();
}
else if (pProp->Type() == eCharacterProperty)
mpWorldEditor->NotifySelectionModified();
}
}
void WModifyTab::OnLinkTableDoubleClick(QModelIndex Index) void WModifyTab::OnLinkTableDoubleClick(QModelIndex Index)
{ {
if (Index.column() == 0) if (Index.column() == 0)

View File

@ -36,7 +36,6 @@ public:
public slots: public slots:
void OnWorldSelectionTransformed(); void OnWorldSelectionTransformed();
void OnPropertyModified(IProperty *pProp);
private: private:
Ui::WModifyTab *ui; Ui::WModifyTab *ui;

View File

@ -13,7 +13,10 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="MainLayout"> <layout class="QVBoxLayout" name="verticalLayout_5">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@ -105,7 +108,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>276</width> <width>276</width>
<height>457</height> <height>460</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">

View File

@ -30,7 +30,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/> <property name="Active" ID="0x255A4580:0x41435456"/>
</properties> </properties>
<assets/> <assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type> <rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type> <scale_type>enabled</scale_type>
</editor> </editor>

View File

@ -18,6 +18,7 @@
<assets> <assets>
<model source="file">script/common/CameraWaypoint.cmdl</model> <model source="file">script/common/CameraWaypoint.cmdl</model>
</assets> </assets>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type> <rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type> <scale_type>enabled</scale_type>
</editor> </editor>

View File

@ -16,6 +16,7 @@
<assets> <assets>
<model source="file">script/common/CameraWaypoint.cmdl</model> <model source="file">script/common/CameraWaypoint.cmdl</model>
</assets> </assets>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type> <rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type> <scale_type>enabled</scale_type>
</editor> </editor>

View File

@ -17,6 +17,7 @@
<assets> <assets>
<model source="file">script/common/SpiderBallWaypoint.cmdl</model> <model source="file">script/common/SpiderBallWaypoint.cmdl</model>
</assets> </assets>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type> <rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type> <scale_type>enabled</scale_type>
</editor> </editor>

View File

@ -25,6 +25,7 @@
<assets> <assets>
<model source="file">script/common/Waypoint.CMDL</model> <model source="file">script/common/Waypoint.CMDL</model>
</assets> </assets>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type> <rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type> <scale_type>enabled</scale_type>
</editor> </editor>

View File

@ -30,7 +30,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/> <property name="Active" ID="0x255A4580:0x41435456"/>
</properties> </properties>
<assets/> <assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type> <rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type> <scale_type>enabled</scale_type>
</editor> </editor>

View File

@ -21,7 +21,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/> <property name="Active" ID="0x255A4580:0x41435456"/>
</properties> </properties>
<assets/> <assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type> <rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type> <scale_type>enabled</scale_type>
</editor> </editor>

View File

@ -21,7 +21,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/> <property name="Active" ID="0x255A4580:0x41435456"/>
</properties> </properties>
<assets/> <assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type> <rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type> <scale_type>enabled</scale_type>
</editor> </editor>

View File

@ -30,7 +30,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/> <property name="Active" ID="0x255A4580:0x41435456"/>
</properties> </properties>
<assets/> <assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type> <rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type> <scale_type>enabled</scale_type>
</editor> </editor>

View File

@ -30,7 +30,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/> <property name="Active" ID="0x255A4580:0x41435456"/>
</properties> </properties>
<assets/> <assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type> <rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type> <scale_type>enabled</scale_type>
</editor> </editor>

View File

@ -21,7 +21,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/> <property name="Active" ID="0x255A4580:0x41435456"/>
</properties> </properties>
<assets/> <assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type> <rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type> <scale_type>enabled</scale_type>
</editor> </editor>