From a46cd5446f548cf1191ad1beff51ce20ab35a103 Mon Sep 17 00:00:00 2001 From: parax0 Date: Sun, 7 Feb 2016 23:48:43 -0700 Subject: [PATCH] Added Editor Properties widget at the top of every World Editor tab, made tons of backend changes to get it to work properly --- src/Core/Core.pro | 1 - src/Core/Resource/Cooker/CScriptCooker.cpp | 6 +- src/Core/Resource/Factory/CAreaLoader.cpp | 2 +- src/Core/Resource/Factory/CScriptLoader.cpp | 8 +- src/Core/Resource/Script/CScriptLayer.cpp | 95 --------- src/Core/Resource/Script/CScriptLayer.h | 103 ++++++--- src/Core/Resource/Script/CScriptObject.cpp | 11 + src/Core/Resource/Script/CScriptObject.h | 7 + src/Core/Resource/Script/IProperty.cpp | 17 +- src/Core/Resource/Script/IProperty.h | 4 +- src/Core/Scene/CScene.cpp | 8 +- src/Core/Scene/CScriptNode.cpp | 2 + src/Editor/Editor.pro | 8 +- src/Editor/PropertyEdit/CPropertyDelegate.cpp | 36 ++-- src/Editor/PropertyEdit/CPropertyModel.cpp | 51 ++++- src/Editor/PropertyEdit/CPropertyModel.h | 7 +- src/Editor/PropertyEdit/CPropertyView.cpp | 27 +-- src/Editor/PropertyEdit/CPropertyView.h | 3 - src/Editor/Undo/CBasicPropertyCommand.cpp | 39 ++-- src/Editor/Undo/CBasicPropertyCommand.h | 7 +- src/Editor/Undo/CChangeLayerCommand.cpp | 42 ++++ src/Editor/Undo/CChangeLayerCommand.h | 22 ++ .../Undo/CEditScriptPropertyCommand.cpp | 9 +- src/Editor/Undo/CEditScriptPropertyCommand.h | 3 +- src/Editor/Undo/CResizeScriptArrayCommand.cpp | 21 +- src/Editor/Undo/CResizeScriptArrayCommand.h | 7 +- src/Editor/Undo/EUndoCommand.h | 2 + src/Editor/Undo/UndoCommands.h | 4 + src/Editor/WorldEditor/CInstancesModel.cpp | 54 ++++- src/Editor/WorldEditor/CInstancesModel.h | 4 + src/Editor/WorldEditor/CWorldEditor.cpp | 151 ++++++++++++-- src/Editor/WorldEditor/CWorldEditor.h | 14 +- src/Editor/WorldEditor/CWorldEditor.ui | 160 ++++++++++++-- src/Editor/WorldEditor/WEditorProperties.cpp | 196 ++++++++++++++++++ src/Editor/WorldEditor/WEditorProperties.h | 51 +++++ src/Editor/WorldEditor/WModifyTab.cpp | 26 +-- src/Editor/WorldEditor/WModifyTab.h | 1 - src/Editor/WorldEditor/WModifyTab.ui | 7 +- templates/dkcr/Script/AIHint.xml | 1 - templates/mp1/Script/CameraWaypoint.xml | 1 + templates/mp1/Script/DebugCameraWaypoint.xml | 1 + templates/mp1/Script/SpiderBallWaypoint.xml | 1 + templates/mp1/Script/Waypoint.xml | 1 + templates/mp2/Script/AIHint.xml | 3 +- templates/mp2/Script/AIJumpPoint.xml | 1 - templates/mp2demo/Script/AIJumpPoint.xml | 1 - templates/mp3/Script/AIHint.xml | 1 - templates/mp3proto/Script/AIHint.xml | 1 - templates/mp3proto/Script/AiJumpPoint.xml | 1 - 49 files changed, 930 insertions(+), 299 deletions(-) delete mode 100644 src/Core/Resource/Script/CScriptLayer.cpp create mode 100644 src/Editor/Undo/CChangeLayerCommand.cpp create mode 100644 src/Editor/Undo/CChangeLayerCommand.h create mode 100644 src/Editor/WorldEditor/WEditorProperties.cpp create mode 100644 src/Editor/WorldEditor/WEditorProperties.h diff --git a/src/Core/Core.pro b/src/Core/Core.pro index 62702aca..8a2f5445 100644 --- a/src/Core/Core.pro +++ b/src/Core/Core.pro @@ -218,7 +218,6 @@ SOURCES += \ Resource/Model/CStaticModel.cpp \ Resource/Model/SSurface.cpp \ Resource/Script/CMasterTemplate.cpp \ - Resource/Script/CScriptLayer.cpp \ Resource/Script/CScriptObject.cpp \ Resource/Script/CScriptTemplate.cpp \ Resource/CAnimationParameters.cpp \ diff --git a/src/Core/Resource/Cooker/CScriptCooker.cpp b/src/Core/Resource/Cooker/CScriptCooker.cpp index ed952ea9..b8e6bc19 100644 --- a/src/Core/Resource/Cooker/CScriptCooker.cpp +++ b/src/Core/Resource/Cooker/CScriptCooker.cpp @@ -116,11 +116,11 @@ void CScriptCooker::WriteLayerMP1(CScriptLayer *pLayer) { u32 LayerStart = mpSCLY->Tell(); 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); } diff --git a/src/Core/Resource/Factory/CAreaLoader.cpp b/src/Core/Resource/Factory/CAreaLoader.cpp index 4ddd48e1..f06c6dbb 100644 --- a/src/Core/Resource/Factory/CAreaLoader.cpp +++ b/src/Core/Resource/Factory/CAreaLoader.cpp @@ -572,7 +572,7 @@ void CAreaLoader::SetUpObjects() if (!pLayer) break; } - for (u32 iObj = 0; iObj < pLayer->GetNumObjects(); iObj++) + for (u32 iObj = 0; iObj < pLayer->NumInstances(); iObj++) { // Add object to object map CScriptObject *pObj = (*pLayer)[iObj]; diff --git a/src/Core/Resource/Factory/CScriptLoader.cpp b/src/Core/Resource/Factory/CScriptLoader.cpp index c60a579b..ff8da8b9 100644 --- a/src/Core/Resource/Factory/CScriptLoader.cpp +++ b/src/Core/Resource/Factory/CScriptLoader.cpp @@ -123,11 +123,11 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY) case eArrayProperty: { CArrayProperty *pArrayCast = static_cast(pProp); - u32 Size = SCLY.ReadLong(); + int Size = SCLY.ReadLong(); pArrayCast->Resize(Size); - for (u32 iElem = 0; iElem < Size; iElem++) + for (int iElem = 0; iElem < Size; iElem++) { if (mVersion < eEchoesDemo) LoadStructMP1(SCLY, static_cast(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate()); @@ -243,7 +243,7 @@ CScriptLayer* CScriptLoader::LoadLayerMP1(IInputStream &SCLY) { CScriptObject *pObj = LoadObjectMP1(SCLY); if (pObj) - mpLayer->AddObject(pObj); + mpLayer->AddInstance(pObj); } // 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); if (pObj) - mpLayer->AddObject(pObj); + mpLayer->AddInstance(pObj); } if (IsSCGN) diff --git a/src/Core/Resource/Script/CScriptLayer.cpp b/src/Core/Resource/Script/CScriptLayer.cpp deleted file mode 100644 index dad5f566..00000000 --- a/src/Core/Resource/Script/CScriptLayer.cpp +++ /dev/null @@ -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; -} diff --git a/src/Core/Resource/Script/CScriptLayer.h b/src/Core/Resource/Script/CScriptLayer.h index 02199532..23079481 100644 --- a/src/Core/Resource/Script/CScriptLayer.h +++ b/src/Core/Resource/Script/CScriptLayer.h @@ -1,5 +1,5 @@ -#ifndef SSCRIPTLAYER_H -#define SSCRIPTLAYER_H +#ifndef CSCRIPTLAYER_H +#define CSCRIPTLAYER_H #include "CScriptObject.h" #include @@ -11,38 +11,85 @@ class CScriptLayer TString mLayerName; bool mActive; bool mVisible; - std::vector mObjects; + std::vector mInstances; public: - CScriptLayer(); - ~CScriptLayer(); + CScriptLayer() + : mLayerName("New Layer") + , mActive(true) + , mVisible(true) + { + } + + ~CScriptLayer() + { + for (auto it = mInstances.begin(); it != mInstances.end(); it++) + delete *it; + } // Data Manipulation - void AddObject(CScriptObject* object); - void DeleteObjectByIndex(u32 index); - void DeleteObjectByID(u32 ID); - void Reserve(u32 amount); + void AddInstance(CScriptObject *pObject) + { + mInstances.push_back(pObject); + } - // Getters and Setters - TString Name(); - bool IsActive(); - bool IsVisible(); - u32 GetNumObjects(); - CScriptObject* ObjectByIndex(u32 index); - CScriptObject* ObjectByID(u32 ID); + void RemoveInstance(CScriptObject *pInstance) + { + for (auto it = mInstances.begin(); it != mInstances.end(); it++) + { + if (*it == pInstance) + { + mInstances.erase(it); + break; + } + } + } - void SetName(const TString& name); - void SetActive(bool active); - void SetVisible(bool visible); + 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); + CScriptObject* operator[](u32 Index) { return InstanceByIndex(Index); } }; -// ************* INLINE FUNCTIONS ************* -inline CScriptObject* CScriptLayer::operator[](u32 index) -{ - return mObjects[index]; -} - - -#endif // SSCRIPTLAYER_H +#endif // CSCRIPTLAYER_H diff --git a/src/Core/Resource/Script/CScriptObject.cpp b/src/Core/Resource/Script/CScriptObject.cpp index 128ddba6..c47e18b4 100644 --- a/src/Core/Resource/Script/CScriptObject.cpp +++ b/src/Core/Resource/Script/CScriptObject.cpp @@ -1,4 +1,5 @@ #include "CScriptObject.h" +#include "CScriptLayer.h" #include "CMasterTemplate.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 ************ IProperty* CScriptObject::PropertyByIndex(u32 index) const { diff --git a/src/Core/Resource/Script/CScriptObject.h b/src/Core/Resource/Script/CScriptObject.h index 0d242d82..44cd563f 100644 --- a/src/Core/Resource/Script/CScriptObject.h +++ b/src/Core/Resource/Script/CScriptObject.h @@ -50,6 +50,7 @@ public: void EvaluateCollisionModel(); void EvaluateVolume(); bool IsEditorProperty(IProperty *pProp); + void SetLayer(CScriptLayer *pLayer); CScriptTemplate* Template() const; CMasterTemplate* MasterTemplate() const; @@ -84,6 +85,12 @@ public: CCollisionMeshGroup* GetCollision() const; EVolumeShape VolumeShape() 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 diff --git a/src/Core/Resource/Script/IProperty.cpp b/src/Core/Resource/Script/IProperty.cpp index 83ac6a4f..0effb6b4 100644 --- a/src/Core/Resource/Script/IProperty.cpp +++ b/src/Core/Resource/Script/IProperty.cpp @@ -2,6 +2,11 @@ #include "IPropertyTemplate.h" // ************ IProperty ************ +CPropertyStruct* IProperty::RootStruct() +{ + return (mpParent ? mpParent->RootStruct() : Type() == eStructProperty ? static_cast(this) : nullptr); +} + IPropertyTemplate* IProperty::Template() const { return mpTemplate; @@ -111,23 +116,23 @@ CPropertyStruct* CPropertyStruct::StructByIDString(const TIDString& rkStr) const } // ************ CArrayProperty ************ -void CArrayProperty::Resize(u32 Size) +void CArrayProperty::Resize(int Size) { - u32 OldSize = mProperties.size(); + int OldSize = mProperties.size(); if (OldSize == Size) return; if (Size < OldSize) { - for (u32 i = mProperties.size() - 1; i >= Size; i--) - delete mProperties[i]; + for (int iProp = mProperties.size() - 1; iProp >= Size; iProp--) + delete mProperties[iProp]; } mProperties.resize(Size); if (Size > OldSize) { - for (u32 i = OldSize; i < Size; i++) - mProperties[i] = static_cast(mpTemplate)->CreateSubStruct(this); + for (int iProp = OldSize; iProp < Size; iProp++) + mProperties[iProp] = static_cast(mpTemplate)->CreateSubStruct(this); } } diff --git a/src/Core/Resource/Script/IProperty.h b/src/Core/Resource/Script/IProperty.h index 44c4e15f..39a40d03 100644 --- a/src/Core/Resource/Script/IProperty.h +++ b/src/Core/Resource/Script/IProperty.h @@ -47,6 +47,8 @@ public: inline CPropertyStruct* Parent() const { return mpParent; } inline void SetParent(CPropertyStruct *pParent) { mpParent = pParent; } + CPropertyStruct* RootStruct(); + // These functions can't be in the header to avoid circular includes with IPropertyTemplate.h IPropertyTemplate* Template() const; TString Name() const; @@ -178,7 +180,7 @@ public: inline void Reserve(u32 amount) { mProperties.reserve(amount); } // Functions - void Resize(u32 Size); + void Resize(int Size); CStructTemplate* SubStructTemplate() const; TString ElementName() const; }; diff --git a/src/Core/Scene/CScene.cpp b/src/Core/Scene/CScene.cpp index 7a9141ff..633c9f61 100644 --- a/src/Core/Scene/CScene.cpp +++ b/src/Core/Scene/CScene.cpp @@ -116,12 +116,12 @@ void CScene::SetActiveArea(CGameArea *pArea) for (u32 iLyr = 0; iLyr < NumLayers; iLyr++) { CScriptLayer *pLayer = mpArea->GetScriptLayer(iLyr); - u32 NumObjects = pLayer->GetNumObjects(); + u32 NumObjects = pLayer->NumInstances(); mNodes[eScriptNode].reserve(mNodes[eScriptNode].size() + NumObjects); for (u32 iObj = 0; iObj < NumObjects; iObj++) { - CScriptObject *pObj = pLayer->ObjectByIndex(iObj); + CScriptObject *pObj = pLayer->InstanceByIndex(iObj); CScriptNode *pNode = CreateScriptNode(pObj); pNode->BuildLightList(mpArea); @@ -142,9 +142,9 @@ void CScene::SetActiveArea(CGameArea *pArea) CScriptLayer *pGenLayer = mpArea->GetGeneratorLayer(); 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); // Add to map diff --git a/src/Core/Scene/CScriptNode.cpp b/src/Core/Scene/CScriptNode.cpp index 2d3e5acf..41ec37d0 100644 --- a/src/Core/Scene/CScriptNode.cpp +++ b/src/Core/Scene/CScriptNode.cpp @@ -191,6 +191,8 @@ void CScriptNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewIn { glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ZERO); glDepthMask(GL_TRUE); + CGraphics::UpdateVertexBlock(); + CGraphics::UpdatePixelBlock(); CDrawUtil::DrawShadedCube(CColor::skTransparentPurple * TintColor(ViewInfo)); } } diff --git a/src/Editor/Editor.pro b/src/Editor/Editor.pro index 5731c88f..b7f1cf71 100644 --- a/src/Editor/Editor.pro +++ b/src/Editor/Editor.pro @@ -137,7 +137,9 @@ HEADERS += \ Undo/CEditScriptPropertyCommand.h \ Undo/CResizeScriptArrayCommand.h \ Undo/CBasicPropertyCommand.h \ - Undo/IUndoCommand.h + Undo/IUndoCommand.h \ + WorldEditor/WEditorProperties.h \ + Undo/CChangeLayerCommand.h # Source Files SOURCES += \ @@ -191,7 +193,9 @@ SOURCES += \ WorldEditor/CInstancesModel.cpp \ Undo/CEditScriptPropertyCommand.cpp \ Undo/CResizeScriptArrayCommand.cpp \ - Undo/CBasicPropertyCommand.cpp + Undo/CBasicPropertyCommand.cpp \ + WorldEditor/WEditorProperties.cpp \ + Undo/CChangeLayerCommand.cpp # UI Files FORMS += \ diff --git a/src/Editor/PropertyEdit/CPropertyDelegate.cpp b/src/Editor/PropertyEdit/CPropertyDelegate.cpp index 3f6b9333..97d303c3 100644 --- a/src/Editor/PropertyEdit/CPropertyDelegate.cpp +++ b/src/Editor/PropertyEdit/CPropertyDelegate.cpp @@ -21,7 +21,7 @@ #define CONNECT_RELAY(Widget, Index, Signal) \ CPropertyRelay *pRelay = new CPropertyRelay(Widget, Index); \ 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*/) : QStyledItemDelegate(pParent) @@ -57,7 +57,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie case eBoolProperty: { QCheckBox *pCheckBox = new QCheckBox(pParent); - CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool)) + CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool)); pOut = pCheckBox; break; } @@ -67,7 +67,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); pSpinBox->setMinimum(INT16_MIN); pSpinBox->setMaximum(INT16_MAX); - CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)) + CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)); pOut = pSpinBox; break; } @@ -77,7 +77,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); pSpinBox->setMinimum(INT32_MIN); pSpinBox->setMaximum(INT32_MAX); - CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)) + CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)); pOut = pSpinBox; break; } @@ -86,15 +86,15 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie { WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent); pSpinBox->setSingleStep(0.1); + CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double)); pOut = pSpinBox; - CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double)) break; } case eColorProperty: { WColorPicker *pColorPicker = new WColorPicker(pParent); - CONNECT_RELAY(pColorPicker, rkIndex, colorChanged(QColor)) + CONNECT_RELAY(pColorPicker, rkIndex, colorChanged(QColor)); pOut = pColorPicker; break; } @@ -102,7 +102,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie case eStringProperty: { QLineEdit *pLineEdit = new QLineEdit(pParent); - CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString)) + CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString)); pOut = pLineEdit; break; } @@ -116,7 +116,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie for (u32 iEnum = 0; iEnum < pTemp->NumEnumerators(); iEnum++) pComboBox->addItem(TO_QSTRING(pTemp->EnumeratorName(iEnum))); - CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int)) + CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int)); pOut = pComboBox; break; } @@ -128,7 +128,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie pSelector->SetAllowedExtensions(pTemp->Extensions()); pSelector->setFont(qobject_cast(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; break; } @@ -159,7 +159,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie else if (pProp->Type() == eBitfieldProperty) { QCheckBox *pCheckBox = new QCheckBox(pParent); - CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool)) + CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool)); pOut = pCheckBox; } @@ -178,7 +178,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie pSpinBox->setMaximum(1.0); } - CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double)) + CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double)); pOut = pSpinBox; } } @@ -194,6 +194,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkIndex) const { BlockRelays(true); + mEditInProgress = false; // fixes case where user does undo mid-edit if (pEditor) { @@ -433,11 +434,11 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo { WIntegralSpinBox *pSpinBox = static_cast(pEditor); CArrayProperty *pArray = static_cast(pProp); - u32 NewCount = pSpinBox->value(); + int NewCount = pSpinBox->value(); if (pArray->Count() != NewCount) { - CResizeScriptArrayCommand *pCmd = new CResizeScriptArrayCommand(mpModel, rkIndex, NewCount); + CResizeScriptArrayCommand *pCmd = new CResizeScriptArrayCommand(pProp, mpEditor, mpModel, NewCount); mpEditor->UndoStack()->push(pCmd); } break; @@ -517,7 +518,8 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo // Create undo command 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); } @@ -563,7 +565,7 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel else pSelector->SetAllowedExtensions("CHAR"); - CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString)) + CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString)); return pSelector; } @@ -579,14 +581,14 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel pComboBox->addItem(TO_QSTRING(pAnimSet->getNodeName(iChr))); } - CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int)) + CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int)); return pComboBox; } if (Type == eLongProperty) { WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); - CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)) + CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)); return pSpinBox; } diff --git a/src/Editor/PropertyEdit/CPropertyModel.cpp b/src/Editor/PropertyEdit/CPropertyModel.cpp index e69dc610..69e00ccc 100644 --- a/src/Editor/PropertyEdit/CPropertyModel.cpp +++ b/src/Editor/PropertyEdit/CPropertyModel.cpp @@ -35,6 +35,48 @@ IProperty* CPropertyModel::PropertyForIndex(const QModelIndex& rkIndex, bool Han return static_cast(rkIndex.internalPointer()); } +QModelIndex CPropertyModel::IndexForProperty(IProperty *pProp) const +{ + if (pProp == mpBaseStruct) return QModelIndex(); + + QVector 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 { return 2; @@ -393,6 +435,11 @@ Qt::ItemFlags CPropertyModel::flags(const QModelIndex& rkIndex) const else return (Qt::ItemIsEnabled | Qt::ItemIsEditable); } +void CPropertyModel::NotifyPropertyModified(IProperty *pProp) +{ + NotifyPropertyModified(IndexForProperty(pProp)); +} + void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex) { if (rowCount(rkIndex) != 0) @@ -405,7 +452,9 @@ void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex) emit dataChanged(Parent, Parent); } - emit dataChanged(rkIndex, rkIndex); + QModelIndex IndexC1 = rkIndex.sibling(rkIndex.row(), 1); + emit dataChanged(IndexC1, IndexC1); + emit PropertyModified(rkIndex); } diff --git a/src/Editor/PropertyEdit/CPropertyModel.h b/src/Editor/PropertyEdit/CPropertyModel.h index f42d9b32..e525cfa3 100644 --- a/src/Editor/PropertyEdit/CPropertyModel.h +++ b/src/Editor/PropertyEdit/CPropertyModel.h @@ -14,6 +14,7 @@ public: CPropertyModel(QObject *pParent = 0); void SetBaseStruct(CPropertyStruct *pBaseStruct); IProperty* PropertyForIndex(const QModelIndex& rkIndex, bool HandleFlaggedPointers) const; + QModelIndex IndexForProperty(IProperty *pProp) const; int columnCount(const QModelIndex& rkParent) const; int rowCount(const QModelIndex& rkParent) const; @@ -23,10 +24,14 @@ public: QModelIndex parent(const QModelIndex& rkChild) const; Qt::ItemFlags flags(const QModelIndex& rkIndex) const; - void NotifyPropertyModified(const QModelIndex& rkIndex); void ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize); void ArrayResized(const QModelIndex& rkIndex, u32 OldSize); void ResizeArray(const QModelIndex& rkIndex, u32 NewSize); + +public slots: + void NotifyPropertyModified(IProperty *pProp); + void NotifyPropertyModified(const QModelIndex& rkIndex); + signals: void PropertyModified(const QModelIndex& rkIndex); }; diff --git a/src/Editor/PropertyEdit/CPropertyView.cpp b/src/Editor/PropertyEdit/CPropertyView.cpp index 7d226d5a..2ea03ef0 100644 --- a/src/Editor/PropertyEdit/CPropertyView.cpp +++ b/src/Editor/PropertyEdit/CPropertyView.cpp @@ -17,7 +17,7 @@ CPropertyView::CPropertyView(QWidget *pParent) connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(SetPersistentEditors(QModelIndex))); connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(edit(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) @@ -66,6 +66,7 @@ void CPropertyView::SetEditor(CWorldEditor *pEditor) { mpEditor = pEditor; mpDelegate->SetEditor(pEditor); + connect(mpEditor, SIGNAL(PropertyModified(IProperty*,bool)), mpModel, SLOT(NotifyPropertyModified(IProperty*))); } void CPropertyView::SetInstance(CScriptObject *pObj) @@ -83,7 +84,10 @@ void CPropertyView::SetInstance(CScriptObject *pObj) 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++) { QModelIndex Index0 = mpModel->index(iRow, 0, rkParent); @@ -92,11 +96,15 @@ void CPropertyView::UpdateEditorProperties(const QModelIndex& rkParent) if (pProp) { + // For structs, update sub-properties. if (pProp->Type() == eStructProperty) { CStructTemplate *pStruct = static_cast(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); else 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. IProperty *pProp = mpModel->PropertyForIndex(rkIndex, true); - if (pProp->Type() == eCharacterProperty && rkIndex.internalId() & 0x1) + if (pProp->Type() == eCharacterProperty /*&& rkIndex.internalId() & 0x1*/) { - EGame Game = static_cast(pProp)->Get().Version(); - - if (mpDelegate->DetermineCharacterPropType(Game, rkIndex) == eFileProperty) - { - ClosePersistentEditors(rkIndex.parent()); - SetPersistentEditors(rkIndex.parent()); - } + ClosePersistentEditors(rkIndex); + SetPersistentEditors(rkIndex); } - - emit PropertyModified(pProp); } diff --git a/src/Editor/PropertyEdit/CPropertyView.h b/src/Editor/PropertyEdit/CPropertyView.h index 7ead912e..df9e8577 100644 --- a/src/Editor/PropertyEdit/CPropertyView.h +++ b/src/Editor/PropertyEdit/CPropertyView.h @@ -29,9 +29,6 @@ public slots: void SetPersistentEditors(const QModelIndex& rkIndex); void ClosePersistentEditors(const QModelIndex& rkIndex); void OnPropertyModified(const QModelIndex& rkIndex); - -signals: - void PropertyModified(IProperty *pProperty); }; #endif // CPROPERTYVIEW_H diff --git a/src/Editor/Undo/CBasicPropertyCommand.cpp b/src/Editor/Undo/CBasicPropertyCommand.cpp index bcb5b483..07ab7060 100644 --- a/src/Editor/Undo/CBasicPropertyCommand.cpp +++ b/src/Editor/Undo/CBasicPropertyCommand.cpp @@ -1,16 +1,16 @@ #include "CBasicPropertyCommand.h" #include -CBasicPropertyCommand::CBasicPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex) - : IUndoCommand("Edit Property") - , mpModel(pModel) - , mpProperty(pModel->PropertyForIndex(rkIndex, true)) +CBasicPropertyCommand::CBasicPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, const QString& rkCommandName /*="Edit Property"*/) + : IUndoCommand(rkCommandName) + , mpProperty(pProp) , mpTemplate(mpProperty->Template()) - , mIndex(rkIndex) + , mpBaseStruct(pProp->RootStruct()) + , mpEditor(pEditor) , mIsInArray(false) { // Check for array - IProperty *pProp = mpProperty; + IProperty *pChild = mpProperty; IProperty *pParent = mpProperty->Parent(); while (pParent) @@ -24,31 +24,28 @@ CBasicPropertyCommand::CBasicPropertyCommand(CPropertyModel *pModel, const QMode for (u32 iSub = 0; iSub < pArray->Count(); iSub++) { - if (pArray->PropertyByIndex(iSub) == pProp) + if (pArray->PropertyByIndex(iSub) == pChild) { mArrayIndices << iSub; break; } } } - pProp = pParent; + pChild = pParent; pParent = pParent->Parent(); } } void CBasicPropertyCommand::UpdateArraySubProperty() { - // If an array has been sized down and then back up, then we might have an index 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. + // 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 pointer is still valid, we'll use the template to find the corresponding property. IPropertyTemplate *pTemp = mpTemplate; CStructTemplate *pParent = mpTemplate->Parent(); QVector SubIndices; int IndexIndex = 0; - if (mIndex.internalId() & 0x1) - SubIndices << mIndex.row(); - while (pParent) { if (pParent->Type() != eArrayProperty || static_cast(pParent)->Count() > 1) @@ -62,6 +59,8 @@ void CBasicPropertyCommand::UpdateArraySubProperty() } } } + else + SubIndices << 0; if (pParent->Type() == eArrayProperty) { @@ -73,15 +72,9 @@ void CBasicPropertyCommand::UpdateArraySubProperty() pParent = pParent->Parent(); } - // Find corresponding index - QModelIndex Index = QModelIndex(); + // Find corresponding property + mpProperty = mpBaseStruct; - for (int iSub = SubIndices.size() - 1; iSub >= 0; iSub--) - Index = mpModel->index(SubIndices[iSub], 0, Index); - - Index = Index.sibling(Index.row(), 1); - - // Get property - mpProperty = mpModel->PropertyForIndex(Index, true); - mIndex = Index; + for (int iChild = SubIndices.size() - 1; iChild >= 0; iChild--) + mpProperty = static_cast(mpProperty)->PropertyByIndex(SubIndices[iChild]); } diff --git a/src/Editor/Undo/CBasicPropertyCommand.h b/src/Editor/Undo/CBasicPropertyCommand.h index c0a186bf..9d4add4a 100644 --- a/src/Editor/Undo/CBasicPropertyCommand.h +++ b/src/Editor/Undo/CBasicPropertyCommand.h @@ -3,20 +3,21 @@ #include "IUndoCommand.h" #include "Editor/PropertyEdit/CPropertyModel.h" +#include "Editor/WorldEditor/CWorldEditor.h" class CBasicPropertyCommand : public IUndoCommand { protected: - CPropertyModel *mpModel; IProperty *mpProperty; IPropertyTemplate *mpTemplate; - QModelIndex mIndex; + CPropertyStruct *mpBaseStruct; + CWorldEditor *mpEditor; bool mIsInArray; QVector mArrayIndices; public: - CBasicPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex); + CBasicPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, const QString& rkCommandName = "Edit Property"); virtual void UpdateArraySubProperty(); virtual bool AffectsCleanState() const { return true; } }; diff --git a/src/Editor/Undo/CChangeLayerCommand.cpp b/src/Editor/Undo/CChangeLayerCommand.cpp new file mode 100644 index 00000000..1911be9b --- /dev/null +++ b/src/Editor/Undo/CChangeLayerCommand.cpp @@ -0,0 +1,42 @@ +#include "CChangeLayerCommand.h" + +CChangeLayerCommand::CChangeLayerCommand(CWorldEditor *pEditor, const QList& 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); +} + diff --git a/src/Editor/Undo/CChangeLayerCommand.h b/src/Editor/Undo/CChangeLayerCommand.h new file mode 100644 index 00000000..589ef50f --- /dev/null +++ b/src/Editor/Undo/CChangeLayerCommand.h @@ -0,0 +1,22 @@ +#ifndef CCHANGELAYERCOMMAND_H +#define CCHANGELAYERCOMMAND_H + +#include "IUndoCommand.h" +#include "Editor/WorldEditor/CWorldEditor.h" +#include + +class CChangeLayerCommand : public IUndoCommand +{ + QList mNodeList; + QMap mOldLayers; + CScriptLayer *mpNewLayer; + CWorldEditor *mpEditor; + +public: + CChangeLayerCommand(CWorldEditor *pEditor, const QList& rkNodeList, CScriptLayer *pNewLayer); + void undo(); + void redo(); + bool AffectsCleanState() const { return true; } +}; + +#endif // CCHANGELAYERCOMMAND_H diff --git a/src/Editor/Undo/CEditScriptPropertyCommand.cpp b/src/Editor/Undo/CEditScriptPropertyCommand.cpp index 80915398..67bd3f1a 100644 --- a/src/Editor/Undo/CEditScriptPropertyCommand.cpp +++ b/src/Editor/Undo/CEditScriptPropertyCommand.cpp @@ -1,8 +1,8 @@ #include "CEditScriptPropertyCommand.h" #include "EUndoCommand.h" -CEditScriptPropertyCommand::CEditScriptPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, IPropertyValue *pOldValue, bool IsDone) - : CBasicPropertyCommand(pModel, rkIndex) +CEditScriptPropertyCommand::CEditScriptPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, IPropertyValue *pOldValue, bool IsDone, const QString& rkCommandName /*= "Edit Property"*/) + : CBasicPropertyCommand(pProp, pEditor, rkCommandName) , mCommandEnded(IsDone) { mpOldValue = pOldValue; @@ -41,12 +41,13 @@ void CEditScriptPropertyCommand::undo() { if (mIsInArray) UpdateArraySubProperty(); mpProperty->RawValue()->Copy(mpOldValue); - mpModel->NotifyPropertyModified(mIndex); + mpEditor->OnPropertyModified(mpProperty); + mCommandEnded = true; } void CEditScriptPropertyCommand::redo() { if (mIsInArray) UpdateArraySubProperty(); mpProperty->RawValue()->Copy(mpNewValue); - mpModel->NotifyPropertyModified(mIndex); + mpEditor->OnPropertyModified(mpProperty); } diff --git a/src/Editor/Undo/CEditScriptPropertyCommand.h b/src/Editor/Undo/CEditScriptPropertyCommand.h index 374610d4..49ff9cc3 100644 --- a/src/Editor/Undo/CEditScriptPropertyCommand.h +++ b/src/Editor/Undo/CEditScriptPropertyCommand.h @@ -3,7 +3,6 @@ #include "CBasicPropertyCommand.h" #include "Editor/PropertyEdit/CPropertyModel.h" -#include class CEditScriptPropertyCommand : public CBasicPropertyCommand { @@ -12,7 +11,7 @@ class CEditScriptPropertyCommand : public CBasicPropertyCommand bool mCommandEnded; 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(); int id() const; bool mergeWith(const QUndoCommand *pkOther); diff --git a/src/Editor/Undo/CResizeScriptArrayCommand.cpp b/src/Editor/Undo/CResizeScriptArrayCommand.cpp index 0812956d..4c1af966 100644 --- a/src/Editor/Undo/CResizeScriptArrayCommand.cpp +++ b/src/Editor/Undo/CResizeScriptArrayCommand.cpp @@ -1,8 +1,9 @@ #include "CResizeScriptArrayCommand.h" -CResizeScriptArrayCommand::CResizeScriptArrayCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, u32 NewSize) - : CBasicPropertyCommand(pModel, rkIndex) +CResizeScriptArrayCommand::CResizeScriptArrayCommand(IProperty *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize) + : CBasicPropertyCommand(pProp, pEditor) , mpArray(static_cast(mpProperty)) + , mpModel(pModel) , mOldSize(mpArray->Count()) , mNewSize(NewSize) { @@ -10,7 +11,7 @@ CResizeScriptArrayCommand::CResizeScriptArrayCommand(CPropertyModel *pModel, con if (!mNewSizeLarger) { - for (u32 iSub = mNewSize; iSub < mOldSize; iSub++) + for (int iSub = mNewSize; iSub < mOldSize; iSub++) { mDeletedProperties << mpArray->PropertyByIndex(iSub)->Clone(); } @@ -29,21 +30,22 @@ void CResizeScriptArrayCommand::undo() { if (mIsInArray) UpdateArraySubProperty(); - mpModel->ArrayAboutToBeResized(mIndex, mOldSize); + QModelIndex Index = mpModel->IndexForProperty(mpProperty); + mpModel->ArrayAboutToBeResized(Index, (u32) mOldSize); mpArray->Resize(mOldSize); 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; 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(); - mpModel->ArrayAboutToBeResized(mIndex, mNewSize); + QModelIndex Index = mpModel->IndexForProperty(mpProperty); + mpModel->ArrayAboutToBeResized(Index, (u32) mNewSize); mpArray->Resize(mNewSize); - mpModel->ArrayResized(mIndex, mOldSize); + mpModel->ArrayResized(Index, (u32) mOldSize); } } diff --git a/src/Editor/Undo/CResizeScriptArrayCommand.h b/src/Editor/Undo/CResizeScriptArrayCommand.h index 082c24e5..05e072dd 100644 --- a/src/Editor/Undo/CResizeScriptArrayCommand.h +++ b/src/Editor/Undo/CResizeScriptArrayCommand.h @@ -9,13 +9,14 @@ class CResizeScriptArrayCommand : public CBasicPropertyCommand { CArrayProperty *mpArray; QVector mDeletedProperties; + CPropertyModel *mpModel; - u32 mOldSize; - u32 mNewSize; + int mOldSize; + int mNewSize; bool mNewSizeLarger; public: - CResizeScriptArrayCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, u32 NewSize); + CResizeScriptArrayCommand(IProperty *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize); ~CResizeScriptArrayCommand(); void undo(); void redo(); diff --git a/src/Editor/Undo/EUndoCommand.h b/src/Editor/Undo/EUndoCommand.h index 2ca6e3ba..b33e7ed0 100644 --- a/src/Editor/Undo/EUndoCommand.h +++ b/src/Editor/Undo/EUndoCommand.h @@ -1,6 +1,8 @@ #ifndef 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 { eTranslateNodeCmd, diff --git a/src/Editor/Undo/UndoCommands.h b/src/Editor/Undo/UndoCommands.h index 0f983796..980f9245 100644 --- a/src/Editor/Undo/UndoCommands.h +++ b/src/Editor/Undo/UndoCommands.h @@ -4,13 +4,17 @@ #include "CTranslateNodeCommand.h" #include "CRotateNodeCommand.h" #include "CScaleNodeCommand.h" + #include "CSelectNodeCommand.h" #include "CDeselectNodeCommand.h" #include "CClearSelectionCommand.h" #include "CSelectAllCommand.h" #include "CInvertSelectionCommand.h" + #include "CEditScriptPropertyCommand.h" #include "CResizeScriptArrayCommand.h" +#include "CChangeLayerCommand.h" + #include "EUndoCommand.h" #endif // UNDOCOMMANDS diff --git a/src/Editor/WorldEditor/CInstancesModel.cpp b/src/Editor/WorldEditor/CInstancesModel.cpp index 17c8a7fa..ab5265e2 100644 --- a/src/Editor/WorldEditor/CInstancesModel.cpp +++ b/src/Editor/WorldEditor/CInstancesModel.cpp @@ -5,7 +5,8 @@ #include #include -/* The tree has 3 levels: +/* + * The tree has 3 levels: * 1. Node Type (Script Object, Light, World Mesh, etc) - represented with ID of 0 * 2. Object Type (Actor, Platform, SpawnPoint, etc) - represented with flags * 3. Instance - represented with pointer to instance (0x1 bit is guaranteed to be clear) @@ -15,6 +16,8 @@ * A: Row index * B: Node type row index * 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_NODE_TYPE_MASK 0x0000001E @@ -87,7 +90,7 @@ QModelIndex CInstancesModel::index(int row, int column, const QModelIndex &paren if (mModelType == eLayers) { CScriptLayer *pLayer = mpArea->GetScriptLayer(parent.row()); - if ((u32) row >= pLayer->GetNumObjects()) + if ((u32) row >= pLayer->NumInstances()) return QModelIndex(); else 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); if (mModelType == eLayers) - return (mpArea ? mpArea->GetScriptLayer(RowIndex)->GetNumObjects() : 0); + return (mpArea ? mpArea->GetScriptLayer(RowIndex)->NumInstances() : 0); else return mTemplateList[RowIndex]->NumObjects(); } @@ -310,8 +313,13 @@ QVariant CInstancesModel::data(const QModelIndex &index, int role) const void CInstancesModel::SetEditor(CWorldEditor *pEditor) { + if (mpEditor) + disconnect(mpEditor, 0, this, 0); + mpEditor = pEditor; mpScene = (pEditor ? pEditor->Scene() : nullptr); + connect(mpEditor, SIGNAL(InstancesLayerAboutToChange()), this, SLOT(InstancesLayerPreChange())); + connect(mpEditor, SIGNAL(InstancesLayerChanged(QList)), this, SLOT(InstancesLayerPostChange(QList))); } void CInstancesModel::SetMaster(CMasterTemplate *pMaster) @@ -404,6 +412,46 @@ CScriptObject* CInstancesModel::IndexObject(const QModelIndex& index) const return static_cast(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& rkInstanceList) +{ + QList 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 ************ CInstancesModel::EIndexType CInstancesModel::IndexType(const QModelIndex& index) { diff --git a/src/Editor/WorldEditor/CInstancesModel.h b/src/Editor/WorldEditor/CInstancesModel.h index f1d402df..c8e68be2 100644 --- a/src/Editor/WorldEditor/CInstancesModel.h +++ b/src/Editor/WorldEditor/CInstancesModel.h @@ -56,6 +56,10 @@ public: CScriptTemplate* IndexTemplate(const QModelIndex& index) const; CScriptObject* IndexObject(const QModelIndex& index) const; +public slots: + void InstancesLayerPreChange(); + void InstancesLayerPostChange(const QList& rkInstanceList); + // Static static EIndexType IndexType(const QModelIndex& index); static ENodeType IndexNodeType(const QModelIndex& index); diff --git a/src/Editor/WorldEditor/CWorldEditor.cpp b/src/Editor/WorldEditor/CWorldEditor.cpp index 25fe9c56..ada7a3a6 100644 --- a/src/Editor/WorldEditor/CWorldEditor.cpp +++ b/src/Editor/WorldEditor/CWorldEditor.cpp @@ -5,6 +5,7 @@ #include "WInstancesTab.h" #include "Editor/CBasicViewport.h" +#include "Editor/PropertyEdit/CPropertyView.h" #include "Editor/Widgets/WDraggableSpinBox.h" #include "Editor/Widgets/WVectorEditor.h" #include "Editor/Undo/UndoCommands.h" @@ -80,6 +81,12 @@ CWorldEditor::CWorldEditor(QWidget *parent) : connect(&mUndoStack, SIGNAL(indexChanged(int)), this, SLOT(OnUndoStackIndexChanged())); 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() @@ -172,18 +179,24 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea, u32 AreaIndex) CStringTable *pWorldNameTable = mpWorld->GetWorldName(); TWideString WorldName = pWorldNameTable ? pWorldNameTable->GetString("ENGL", 0) : "[Untitled World]"; - CStringTable *pAreaNameTable = mpWorld->GetAreaName(AreaIndex); - TWideString AreaName = pAreaNameTable ? pAreaNameTable->GetString("ENGL", 0) : (TWideString("!") + mpWorld->GetAreaInternalName(AreaIndex).ToUTF16()); + if (CurrentGame() < eReturns) + { + CStringTable *pAreaNameTable = mpWorld->GetAreaName(AreaIndex); + TWideString AreaName = pAreaNameTable ? pAreaNameTable->GetString("ENGL", 0) : (TWideString("!") + mpWorld->GetAreaInternalName(AreaIndex).ToUTF16()); - if (AreaName.IsEmpty()) - AreaName = "[Untitled Area]"; + if (AreaName.IsEmpty()) + AreaName = "[Untitled Area]"; - 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() -{ - return mpArea; + else + { + setWindowTitle(QString("Prime World Editor - %1[*]").arg(TO_QSTRING(WorldName))); + } + + // Emit signals + emit LayersModified(); } 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(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(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 Objects; + + foreach (CSceneNode *pNode, mSelection) + { + if (pNode->NodeType() == eScriptNode) + { + CScriptNode *pScript = static_cast(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(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 ScriptNodes; + + foreach (CSceneNode *pNode, mSelection) + { + if (pNode->NodeType() == eScriptNode) + ScriptNodes << static_cast(pNode); + } + + if (!ScriptNodes.isEmpty()) + mUndoStack.push(new CChangeLayerCommand(this, ScriptNodes, pLayer)); +} + void CWorldEditor::UpdateStatusBar() { // 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); - if (pkQCmd->childCount() > 0) + if (const IUndoCommand *pkCmd = dynamic_cast(pkQCmd)) + { + if (pkCmd->AffectsCleanState()) + IsClean = false; + } + + else if (pkQCmd->childCount() > 0) { for (int iChild = 0; iChild < pkQCmd->childCount(); iChild++) { @@ -382,14 +505,6 @@ void CWorldEditor::OnUndoStackIndexChanged() } } - else - { - const IUndoCommand *pkCmd = static_cast(pkQCmd); - - if (pkCmd->AffectsCleanState()) - IsClean = false; - } - if (!IsClean) break; } diff --git a/src/Editor/WorldEditor/CWorldEditor.h b/src/Editor/WorldEditor/CWorldEditor.h index 3445c739..0844c2d8 100644 --- a/src/Editor/WorldEditor/CWorldEditor.h +++ b/src/Editor/WorldEditor/CWorldEditor.h @@ -43,11 +43,17 @@ public: void closeEvent(QCloseEvent *pEvent); bool eventFilter(QObject *pObj, QEvent *pEvent); void SetArea(CWorld *pWorld, CGameArea *pArea, u32 AreaIndex); - CGameArea* ActiveArea(); bool CheckUnsavedChanges(); + inline CGameArea* ActiveArea() const { return mpArea; } + inline EGame CurrentGame() const { return mpArea->Version(); } + public slots: bool Save(); + void OnPropertyModified(IProperty *pProp); + void SetSelectionActive(bool Active); + void SetSelectionInstanceNames(const QString& rkNewName, bool IsDone); + void SetSelectionLayer(CScriptLayer *pLayer); void UpdateStatusBar(); void UpdateGizmoUI(); @@ -89,6 +95,12 @@ private slots: void on_ActionSelectAll_triggered(); void on_ActionInvertSelection_triggered(); void on_ActionEditPoiToWorldMap_triggered(); + +signals: + void LayersModified(); + void InstancesLayerAboutToChange(); + void InstancesLayerChanged(const QList& rkInstanceList); + void PropertyModified(IProperty *pProp, bool IsEditorProperty); }; #endif // CWORLDEDITOR_H diff --git a/src/Editor/WorldEditor/CWorldEditor.ui b/src/Editor/WorldEditor/CWorldEditor.ui index 554a0b68..321bd541 100644 --- a/src/Editor/WorldEditor/CWorldEditor.ui +++ b/src/Editor/WorldEditor/CWorldEditor.ui @@ -20,7 +20,7 @@ Qt::Horizontal - + @@ -251,19 +251,7 @@ Create - - - - - :/icons/Modify.png:/icons/Modify.png - - - - - - Modify - - + 0 @@ -277,7 +265,62 @@ 0 - + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + :/icons/Modify.png:/icons/Modify.png + + + + + + Modify + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + 0 + + + @@ -292,7 +335,7 @@ Instances - + 0 @@ -306,7 +349,24 @@ 0 - + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + @@ -321,6 +381,36 @@ Display + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + @@ -333,6 +423,36 @@ World + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + @@ -771,6 +891,12 @@
Editor/CSceneViewport.h
1 + + WEditorProperties + QWidget +
Editor/WorldEditor/WEditorProperties.h
+ 1 +
diff --git a/src/Editor/WorldEditor/WEditorProperties.cpp b/src/Editor/WorldEditor/WEditorProperties.cpp new file mode 100644 index 00000000..1dae4ab7 --- /dev/null +++ b/src/Editor/WorldEditor/WEditorProperties.cpp @@ -0,0 +1,196 @@ +#include "WEditorProperties.h" +#include "Editor/Undo/CEditScriptPropertyCommand.h" +#include + +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)), this, SLOT(OnInstancesLayerChanged(QList))); + 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(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& 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& 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(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); + } +} + diff --git a/src/Editor/WorldEditor/WEditorProperties.h b/src/Editor/WorldEditor/WEditorProperties.h new file mode 100644 index 00000000..abba88c9 --- /dev/null +++ b/src/Editor/WorldEditor/WEditorProperties.h @@ -0,0 +1,51 @@ +#ifndef WEDITORPROPERTIES_H +#define WEDITORPROPERTIES_H + +#include +#include "CWorldEditor.h" + +#include +#include +#include +#include +#include +#include + +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& rkNodeList); + void OnLayersModified(); + void UpdatePropertyValues(); + +protected slots: + void OnActiveChanged(); + void OnInstanceNameEdited(); + void OnInstanceNameEditFinished(); + void OnLayerChanged(); +}; + +#endif // WEDITORPROPERTIES_H diff --git a/src/Editor/WorldEditor/WModifyTab.cpp b/src/Editor/WorldEditor/WModifyTab.cpp index 29bd2797..adddc265 100644 --- a/src/Editor/WorldEditor/WModifyTab.cpp +++ b/src/Editor/WorldEditor/WModifyTab.cpp @@ -16,7 +16,6 @@ WModifyTab::WModifyTab(QWidget *pParent) : ui->PropertyView->header()->resizeSection(0, PropViewWidth * 0.3); ui->PropertyView->header()->resizeSection(1, PropViewWidth * 0.3); ui->PropertyView->header()->setSectionResizeMode(1, QHeaderView::Fixed); - connect(ui->PropertyView, SIGNAL(PropertyModified(IProperty*)), this, SLOT(OnPropertyModified(IProperty*))); mpInLinkModel = new CLinkModel(this); mpInLinkModel->SetConnectionType(CLinkModel::eIncoming); @@ -86,30 +85,7 @@ void WModifyTab::OnWorldSelectionTransformed() ui->PropertyView->UpdateEditorProperties(QModelIndex()); } -void WModifyTab::OnPropertyModified(IProperty *pProp) -{ - if (mpSelectedNode->NodeType() == eScriptNode) - { - CScriptNode *pNode = static_cast(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(pProp->Template()); - - if (pFile->AcceptsExtension("CMDL") || pFile->AcceptsExtension("ANCS") || pFile->AcceptsExtension("CHAR")) - mpWorldEditor->NotifySelectionModified(); - } - else if (pProp->Type() == eCharacterProperty) - mpWorldEditor->NotifySelectionModified(); - } -} - +// ************ PRIVATE SLOTS ************ void WModifyTab::OnLinkTableDoubleClick(QModelIndex Index) { if (Index.column() == 0) diff --git a/src/Editor/WorldEditor/WModifyTab.h b/src/Editor/WorldEditor/WModifyTab.h index 3db5c816..dd9384e6 100644 --- a/src/Editor/WorldEditor/WModifyTab.h +++ b/src/Editor/WorldEditor/WModifyTab.h @@ -36,7 +36,6 @@ public: public slots: void OnWorldSelectionTransformed(); - void OnPropertyModified(IProperty *pProp); private: Ui::WModifyTab *ui; diff --git a/src/Editor/WorldEditor/WModifyTab.ui b/src/Editor/WorldEditor/WModifyTab.ui index 912d63f0..907a1e7e 100644 --- a/src/Editor/WorldEditor/WModifyTab.ui +++ b/src/Editor/WorldEditor/WModifyTab.ui @@ -13,7 +13,10 @@ Form - + + + 3 + 0 @@ -105,7 +108,7 @@ 0 0 276 - 457 + 460 diff --git a/templates/dkcr/Script/AIHint.xml b/templates/dkcr/Script/AIHint.xml index f90b77cf..b4127028 100644 --- a/templates/dkcr/Script/AIHint.xml +++ b/templates/dkcr/Script/AIHint.xml @@ -30,7 +30,6 @@ - 0.5 enabled enabled diff --git a/templates/mp1/Script/CameraWaypoint.xml b/templates/mp1/Script/CameraWaypoint.xml index d759056f..15b7f15c 100644 --- a/templates/mp1/Script/CameraWaypoint.xml +++ b/templates/mp1/Script/CameraWaypoint.xml @@ -18,6 +18,7 @@ script/common/CameraWaypoint.cmdl + 0.5 enabled enabled diff --git a/templates/mp1/Script/DebugCameraWaypoint.xml b/templates/mp1/Script/DebugCameraWaypoint.xml index 983f46db..35f97064 100644 --- a/templates/mp1/Script/DebugCameraWaypoint.xml +++ b/templates/mp1/Script/DebugCameraWaypoint.xml @@ -16,6 +16,7 @@ script/common/CameraWaypoint.cmdl + 0.5 enabled enabled diff --git a/templates/mp1/Script/SpiderBallWaypoint.xml b/templates/mp1/Script/SpiderBallWaypoint.xml index 20fe5d04..605be6ee 100644 --- a/templates/mp1/Script/SpiderBallWaypoint.xml +++ b/templates/mp1/Script/SpiderBallWaypoint.xml @@ -17,6 +17,7 @@ script/common/SpiderBallWaypoint.cmdl + 0.5 enabled enabled diff --git a/templates/mp1/Script/Waypoint.xml b/templates/mp1/Script/Waypoint.xml index 0a1c76e8..384b49e0 100644 --- a/templates/mp1/Script/Waypoint.xml +++ b/templates/mp1/Script/Waypoint.xml @@ -25,6 +25,7 @@ script/common/Waypoint.CMDL + 0.5 enabled enabled diff --git a/templates/mp2/Script/AIHint.xml b/templates/mp2/Script/AIHint.xml index f90b77cf..ce54c290 100644 --- a/templates/mp2/Script/AIHint.xml +++ b/templates/mp2/Script/AIHint.xml @@ -1,4 +1,4 @@ - + AIHint @@ -30,7 +30,6 @@ - 0.5 enabled enabled diff --git a/templates/mp2/Script/AIJumpPoint.xml b/templates/mp2/Script/AIJumpPoint.xml index 0b3af57a..a9f897f9 100644 --- a/templates/mp2/Script/AIJumpPoint.xml +++ b/templates/mp2/Script/AIJumpPoint.xml @@ -21,7 +21,6 @@ - 0.5 enabled enabled diff --git a/templates/mp2demo/Script/AIJumpPoint.xml b/templates/mp2demo/Script/AIJumpPoint.xml index 0b3af57a..a9f897f9 100644 --- a/templates/mp2demo/Script/AIJumpPoint.xml +++ b/templates/mp2demo/Script/AIJumpPoint.xml @@ -21,7 +21,6 @@ - 0.5 enabled enabled diff --git a/templates/mp3/Script/AIHint.xml b/templates/mp3/Script/AIHint.xml index f90b77cf..b4127028 100644 --- a/templates/mp3/Script/AIHint.xml +++ b/templates/mp3/Script/AIHint.xml @@ -30,7 +30,6 @@ - 0.5 enabled enabled diff --git a/templates/mp3proto/Script/AIHint.xml b/templates/mp3proto/Script/AIHint.xml index f90b77cf..b4127028 100644 --- a/templates/mp3proto/Script/AIHint.xml +++ b/templates/mp3proto/Script/AIHint.xml @@ -30,7 +30,6 @@ - 0.5 enabled enabled diff --git a/templates/mp3proto/Script/AiJumpPoint.xml b/templates/mp3proto/Script/AiJumpPoint.xml index 43a6db81..985f0068 100644 --- a/templates/mp3proto/Script/AiJumpPoint.xml +++ b/templates/mp3proto/Script/AiJumpPoint.xml @@ -21,7 +21,6 @@ - 0.5 enabled enabled