Added TPropCast property casting function, added support for clean/dirty state in the world editor + check for unsaved changes when the window is closed

This commit is contained in:
parax0 2016-02-01 16:42:12 -07:00
parent 6669dd4367
commit 1a07a9c083
34 changed files with 242 additions and 163 deletions

View File

@ -18,7 +18,7 @@ class CLightParameters
EGame mGame;
TLongProperty *mpLightLayer;
TLongProperty *mpWorldLightingOptions;
TEnumProperty *mpWorldLightingOptions;
public:
CLightParameters(CPropertyStruct *pStruct, EGame Game)
@ -31,13 +31,13 @@ public:
{
if (mGame <= ePrime)
{
mpWorldLightingOptions = (TLongProperty*) mpStruct->PropertyByIndex(0x7);
mpLightLayer = (TLongProperty*) mpStruct->PropertyByIndex(0xD);
mpWorldLightingOptions = TPropCast<TEnumProperty>(mpStruct->PropertyByIndex(0x7));
mpLightLayer = TPropCast<TLongProperty>(mpStruct->PropertyByIndex(0xD));
}
else
{
mpWorldLightingOptions = (TLongProperty*) mpStruct->PropertyByIndex(0x6B5E7509);
mpLightLayer = (TLongProperty*) mpStruct->PropertyByID(0x1F715FD3);
mpWorldLightingOptions = TPropCast<TEnumProperty>(mpStruct->PropertyByID(0x6B5E7509));
mpLightLayer = TPropCast<TLongProperty>(mpStruct->PropertyByID(0x1F715FD3));
}
}
}

View File

@ -71,6 +71,8 @@ public:
~TTypedProperty() {}
virtual EPropertyType Type() const { return TypeEnum; }
static inline EPropertyType StaticType() { return TypeEnum; }
virtual TString ToString() const { return mValue.ToString(); }
virtual IPropertyValue* RawValue() { return &mValue; }
@ -124,6 +126,7 @@ public:
}
EPropertyType Type() const { return eStructProperty; }
static inline EPropertyType StaticType() { return eStructProperty; }
virtual void Copy(const IProperty *pkProp);
@ -161,6 +164,7 @@ public:
: CPropertyStruct(pTemp, pParent) {}
EPropertyType Type() const { return eArrayProperty; }
static inline EPropertyType StaticType() { return eArrayProperty; }
virtual IProperty* Clone(CPropertyStruct *pParent) const
{
@ -179,5 +183,14 @@ public:
TString ElementName() const;
};
/*
* Function for casting properties. Returns null if the property is not actually the requested type.
*/
template <class PropertyClass>
PropertyClass* TPropCast(IProperty *pProp)
{
return (pProp && pProp->Type() == PropertyClass::StaticType() ? static_cast<PropertyClass*>(pProp) : nullptr);
}
#endif // IPROPERTY

View File

@ -76,9 +76,6 @@ ENodeType CScriptNode::NodeType()
void CScriptNode::OnTransformed()
{
if (mpExtra)
mpExtra->OnTransformed();
if (mpInstance)
{
CScriptTemplate *pTemplate = Template();
@ -92,6 +89,9 @@ void CScriptNode::OnTransformed()
if (pTemplate->HasScale() && LocalScale() != mpInstance->Scale())
mpInstance->SetScale(LocalScale());
}
if (mpExtra)
mpExtra->OnTransformed();
}
void CScriptNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
@ -167,7 +167,6 @@ void CScriptNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewIn
else
{
LoadLights(ViewInfo);
CGraphics::UpdateLightBlock();
}
LoadModelMatrix();

View File

@ -16,36 +16,18 @@ CDamageableTriggerExtra::CDamageableTriggerExtra(CScriptObject *pInstance, CScen
CPropertyStruct *pBaseStruct = pInstance->Properties();
// Fetch render side
mpRenderSideProp = (TEnumProperty*) pBaseStruct->PropertyByIndex(0x5);
if (mpRenderSideProp && mpRenderSideProp->Type() != eEnumProperty)
mpRenderSideProp = nullptr;
mpRenderSideProp = TPropCast<TEnumProperty>(pBaseStruct->PropertyByIndex(0x5));
if (mpRenderSideProp) PropertyModified(mpRenderSideProp);
// Fetch scale
mpSizeProp = (TVector3Property*) pBaseStruct->PropertyByIndex(0x2);
if (mpSizeProp && mpSizeProp->Type() != eVector3Property)
mpSizeProp = nullptr;
if (mpSizeProp) PropertyModified (mpSizeProp);
mpSizeProp = TPropCast<TVector3Property>(pBaseStruct->PropertyByIndex(0x2));
if (mpSizeProp) PropertyModified(mpSizeProp);
// Fetch textures
for (u32 iTex = 0; iTex < 3; iTex++)
{
mpTextureProps[iTex] = (TFileProperty*) pBaseStruct->PropertyByIndex(0x6 + iTex);
if (mpTextureProps[iTex])
{
if (mpTextureProps[iTex]->Type() == eFileProperty)
PropertyModified(mpTextureProps[iTex]);
else
mpTextureProps[iTex] = nullptr;
}
else
mpTextures[iTex] = nullptr;
mpTextureProps[iTex] = TPropCast<TFileProperty>(pBaseStruct->PropertyByIndex(0x6 + iTex));
if (mpTextureProps[iTex]) PropertyModified(mpTextureProps[iTex]);
}
}
@ -147,6 +129,12 @@ void CDamageableTriggerExtra::UpdatePlaneTransform()
MarkTransformChanged();
}
void CDamageableTriggerExtra::OnTransformed()
{
mPlaneSize = mpSizeProp->Get();
UpdatePlaneTransform();
}
void CDamageableTriggerExtra::PropertyModified(IProperty *pProperty)
{
if (pProperty == mpRenderSideProp)

View File

@ -35,6 +35,7 @@ public:
~CDamageableTriggerExtra();
void CreateMaterial();
void UpdatePlaneTransform();
void OnTransformed();
void PropertyModified(IProperty *pProperty);
bool ShouldDrawNormalAssets();
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);

View File

@ -9,31 +9,19 @@ CDoorExtra::CDoorExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pPa
{
CPropertyStruct *pBaseStruct = pInstance->Properties();
mpShieldModelProp = (TFileProperty*) pBaseStruct->PropertyByID(0xB20CC271);
if (mpShieldModelProp && (mpShieldModelProp->Type() != eFileProperty))
mpShieldModelProp = nullptr;
if (mpShieldModelProp)
PropertyModified(mpShieldModelProp);
mpShieldModelProp = TPropCast<TFileProperty>(pBaseStruct->PropertyByID(0xB20CC271));
if (mpShieldModelProp) PropertyModified(mpShieldModelProp);
if (mGame >= eEchoes)
{
mpShieldColorProp = (TColorProperty*) pBaseStruct->PropertyByID(0x47B4E863);
if (mpShieldColorProp && (mpShieldColorProp->Type() != eColorProperty))
mpShieldColorProp = nullptr;
if (mpShieldColorProp)
PropertyModified(mpShieldColorProp);
mpShieldColorProp = TPropCast<TColorProperty>(pBaseStruct->PropertyByID(0x47B4E863));
if (mpShieldColorProp) PropertyModified(mpShieldColorProp);
}
else
{
mpDisabledProp = (TBoolProperty*) pBaseStruct->PropertyByID(0xDEE730F5);
if (mpDisabledProp && (mpDisabledProp->Type() != eBoolProperty))
mpDisabledProp = nullptr;
if (mpDisabledProp)
PropertyModified(mpDisabledProp);
mpDisabledProp = TPropCast<TBoolProperty>(pBaseStruct->PropertyByID(0xDEE730F5));
if (mpDisabledProp) PropertyModified(mpDisabledProp);
}
}

View File

@ -11,32 +11,9 @@ CPointOfInterestExtra::CPointOfInterestExtra(CScriptObject *pInstance, CScene *p
// Fetch scan data property
CPropertyStruct *pBaseProp = pInstance->Properties();
switch (mGame)
{
case ePrimeDemo:
case ePrime:
mpScanProperty = (TFileProperty*) pBaseProp->PropertyByIDString("0x04:0x00");
break;
case eEchoesDemo:
case eEchoes:
case eCorruptionProto:
case eCorruption:
mpScanProperty = (TFileProperty*) pBaseProp->PropertyByIDString("0xBDBEC295:0xB94E9BE7");
break;
default:
mpScanProperty = nullptr;
break;
}
if (mpScanProperty)
{
if (mpScanProperty->Type() == eFileProperty)
PropertyModified(mpScanProperty);
else
mpScanProperty = nullptr;
}
if (mGame <= ePrime) mpScanProperty = TPropCast<TFileProperty>(pBaseProp->PropertyByIDString("0x04:0x00"));
else mpScanProperty = (TFileProperty*) pBaseProp->PropertyByIDString("0xBDBEC295:0xB94E9BE7");
if (mpScanProperty) PropertyModified(mpScanProperty);
}
void CPointOfInterestExtra::PropertyModified(IProperty* pProperty)

View File

@ -11,16 +11,16 @@ CRadiusSphereExtra::CRadiusSphereExtra(CScriptObject *pInstance, CScene *pScene,
switch (mObjectType)
{
case 0x63: // Repulsor (MP1)
mpRadius = (TFloatProperty*) pInstance->Properties()->PropertyByID(0x3);
mpRadius = TPropCast<TFloatProperty>(pInstance->Properties()->PropertyByID(0x3));
break;
case 0x68: // RadialDamage (MP1)
mpRadius = (TFloatProperty*) pInstance->Properties()->PropertyByID(0x4);
mpRadius = TPropCast<TFloatProperty>(pInstance->Properties()->PropertyByID(0x4));
break;
case 0x5245504C: // "REPL" Repulsor (MP2/MP3)
case 0x52414444: // "RADD" RadialDamage (MP2/MP3/DKCR)
mpRadius = (TFloatProperty*) pInstance->Properties()->PropertyByID(0x78C507EB);
mpRadius = TPropCast<TFloatProperty>(pInstance->Properties()->PropertyByID(0x78C507EB));
break;
}
}

View File

@ -12,21 +12,10 @@ CSpacePirateExtra::CSpacePirateExtra(CScriptObject *pInstance, CScene *pScene, C
if (pVulns && pVulns->Type() == eStructProperty)
{
mpPowerVuln = (TLongProperty*) pVulns->PropertyByID(0x0);
if (mpPowerVuln && mpPowerVuln->Type() != eLongProperty && mpPowerVuln->Type() != eEnumProperty)
mpPowerVuln = nullptr;
mpWaveVuln = (TLongProperty*) pVulns->PropertyByID(0x2);
if (mpWaveVuln && mpWaveVuln->Type() != eLongProperty && mpWaveVuln->Type() != eEnumProperty)
mpWaveVuln = nullptr;
mpIceVuln = (TLongProperty*) pVulns->PropertyByID(0x1);
if (mpIceVuln && mpIceVuln->Type() != eLongProperty && mpIceVuln->Type() != eEnumProperty)
mpIceVuln = nullptr;
mpPlasmaVuln = (TLongProperty*) pVulns->PropertyByID(0x3);
if (mpPlasmaVuln && mpPlasmaVuln->Type() != eLongProperty && mpPlasmaVuln->Type() != eEnumProperty)
mpPlasmaVuln = nullptr;
mpPowerVuln = TPropCast<TEnumProperty>(pVulns->PropertyByID(0x0));
mpWaveVuln = TPropCast<TEnumProperty>(pVulns->PropertyByID(0x2));
mpIceVuln = TPropCast<TEnumProperty>(pVulns->PropertyByID(0x1));
mpPlasmaVuln = TPropCast<TEnumProperty>(pVulns->PropertyByID(0x3));
}
}

View File

@ -7,10 +7,10 @@
class CSpacePirateExtra : public CScriptExtra
{
// Render beam troopers with the correct color
TLongProperty *mpPowerVuln;
TLongProperty *mpWaveVuln;
TLongProperty *mpIceVuln;
TLongProperty *mpPlasmaVuln;
TEnumProperty *mpPowerVuln;
TEnumProperty *mpWaveVuln;
TEnumProperty *mpIceVuln;
TEnumProperty *mpPlasmaVuln;
public:
explicit CSpacePirateExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0);

View File

@ -134,7 +134,7 @@ void CStartWindow::FillAreaUI()
if (AttachedAreaSTRG)
AttachedStr = TO_QSTRING(AttachedAreaSTRG->GetString("ENGL", 0));
else
AttachedStr = QString("!!") + TO_QSTRING(mpWorld->GetAreaInternalName(AttachedAreaIndex));
AttachedStr = QString("!") + TO_QSTRING(mpWorld->GetAreaInternalName(AttachedAreaIndex));
ui->AttachedAreasList->addItem(AttachedStr);
}
@ -168,7 +168,7 @@ void CStartWindow::on_LaunchWorldEditorButton_clicked()
else
{
mpWorld->SetAreaLayerInfo(pArea, mSelectedAreaIndex);
mpWorldEditor->SetArea(mpWorld, pArea);
mpWorldEditor->SetArea(mpWorld, pArea, mSelectedAreaIndex);
mpWorldEditor->setWindowModality(Qt::WindowModal);
mpWorldEditor->showMaximized();

View File

@ -136,7 +136,8 @@ HEADERS += \
WorldEditor/CInstancesModel.h \
Undo/CEditScriptPropertyCommand.h \
Undo/CResizeScriptArrayCommand.h \
Undo/CBasicPropertyCommand.h
Undo/CBasicPropertyCommand.h \
Undo/IUndoCommand.h
# Source Files
SOURCES += \

View File

@ -2,7 +2,7 @@
#include <Core/Resource/Script/IPropertyTemplate.h>
CBasicPropertyCommand::CBasicPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex)
: QUndoCommand("Edit Property")
: IUndoCommand("Edit Property")
, mpModel(pModel)
, mpProperty(pModel->PropertyForIndex(rkIndex, true))
, mpTemplate(mpProperty->Template())

View File

@ -1,10 +1,10 @@
#ifndef CBASICPROPERTYCOMMAND_H
#define CBASICPROPERTYCOMMAND_H
#include "IUndoCommand.h"
#include "Editor/PropertyEdit/CPropertyModel.h"
#include <QUndoCommand>
class CBasicPropertyCommand : public QUndoCommand
class CBasicPropertyCommand : public IUndoCommand
{
protected:
CPropertyModel *mpModel;
@ -18,6 +18,7 @@ protected:
public:
CBasicPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex);
virtual void UpdateArraySubProperty();
virtual bool AffectsCleanState() const { return true; }
};
#endif // CBASICPROPERTYCOMMAND_H

View File

@ -2,7 +2,7 @@
#include "Editor/INodeEditor.h"
CClearSelectionCommand::CClearSelectionCommand(INodeEditor *pEditor, QList<CSceneNode*>& selection)
: QUndoCommand("Clear Selection"),
: IUndoCommand("Clear Selection"),
mpEditor(pEditor),
mSelectionState(selection),
mpSelection(&selection)

View File

@ -1,12 +1,11 @@
#ifndef CCLEARSELECTIONCOMMAND_H
#define CCLEARSELECTIONCOMMAND_H
#include "IUndoCommand.h"
#include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h>
#include <QUndoCommand>
class CClearSelectionCommand : public QUndoCommand
class CClearSelectionCommand : public IUndoCommand
{
INodeEditor *mpEditor;
QList<CSceneNode*> mSelectionState;
@ -16,6 +15,7 @@ public:
~CClearSelectionCommand();
void undo();
void redo();
bool AffectsCleanState() const { return false; }
};
#endif // CCLEARSELECTIONCOMMAND_H

View File

@ -2,7 +2,7 @@
#include "Editor/INodeEditor.h"
CDeselectNodeCommand::CDeselectNodeCommand(INodeEditor *pEditor, CSceneNode *pNode, QList<CSceneNode*>& selection)
: QUndoCommand("Deselect"),
: IUndoCommand("Deselect"),
mpEditor(pEditor),
mpNode(pNode),
mpSelection(&selection)

View File

@ -1,12 +1,11 @@
#ifndef CDESELECTNODECOMMAND_H
#define CDESELECTNODECOMMAND_H
#include "IUndoCommand.h"
#include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h>
#include <QUndoCommand>
class CDeselectNodeCommand : public QUndoCommand
class CDeselectNodeCommand : public IUndoCommand
{
INodeEditor *mpEditor;
CSceneNode *mpNode;
@ -15,6 +14,7 @@ public:
CDeselectNodeCommand(INodeEditor *pEditor, CSceneNode *pNode, QList<CSceneNode*>& selection);
void undo();
void redo();
bool AffectsCleanState() const { return false; }
};
#endif // CDESELECTNODECOMMAND_H

View File

@ -2,7 +2,7 @@
#include <Core/Scene/CSceneIterator.h>
CInvertSelectionCommand::CInvertSelectionCommand(INodeEditor *pEditor, QList<CSceneNode*>& rSelection, CScene *pScene, FNodeFlags NodeFlags)
: QUndoCommand("Invert Selection")
: IUndoCommand("Invert Selection")
, mpEditor(pEditor)
, mOldSelection(rSelection)
, mpSelection(&rSelection)

View File

@ -1,12 +1,11 @@
#ifndef CINVERTSELECTIONCOMMAND_H
#define CINVERTSELECTIONCOMMAND_H
#include "IUndoCommand.h"
#include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h>
#include <QUndoCommand>
class CInvertSelectionCommand : public QUndoCommand
class CInvertSelectionCommand : public IUndoCommand
{
INodeEditor *mpEditor;
QList<CSceneNode*> mOldSelection;
@ -18,6 +17,7 @@ public:
~CInvertSelectionCommand();
void undo();
void redo();
virtual bool AffectsCleanState() const { return false; }
};
#endif // CINVERTSELECTIONCOMMAND_H

View File

@ -3,14 +3,14 @@
#include "Editor/INodeEditor.h"
CRotateNodeCommand::CRotateNodeCommand()
: QUndoCommand("Rotate"),
: IUndoCommand("Rotate"),
mpEditor(nullptr),
mCommandEnded(false)
{
}
CRotateNodeCommand::CRotateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& /*pivot*/, const CQuaternion& delta, ETransformSpace transformSpace)
: QUndoCommand("Rotate"),
: IUndoCommand("Rotate"),
mpEditor(pEditor),
mCommandEnded(false)
{

View File

@ -1,13 +1,12 @@
#ifndef CROTATENODECOMMAND_H
#define CROTATENODECOMMAND_H
#include "IUndoCommand.h"
#include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h>
#include <QUndoCommand>
#include <QList>
class CRotateNodeCommand : public QUndoCommand
class CRotateNodeCommand : public IUndoCommand
{
struct SNodeRotate
{
@ -29,6 +28,7 @@ public:
bool mergeWith(const QUndoCommand *other);
void undo();
void redo();
bool AffectsCleanState() const { return true; }
static CRotateNodeCommand* End();
};

View File

@ -3,14 +3,14 @@
#include "Editor/INodeEditor.h"
CScaleNodeCommand::CScaleNodeCommand()
: QUndoCommand("Scale"),
: IUndoCommand("Scale"),
mpEditor(nullptr),
mCommandEnded(false)
{
}
CScaleNodeCommand::CScaleNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& /*pivot*/, const CVector3f& delta)
: QUndoCommand("Scale"),
: IUndoCommand("Scale"),
mpEditor(pEditor),
mCommandEnded(false)
{

View File

@ -1,13 +1,12 @@
#ifndef CSCALENODECOMMAND_H
#define CSCALENODECOMMAND_H
#include "IUndoCommand.h"
#include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h>
#include <QUndoCommand>
#include <QList>
class CScaleNodeCommand : public QUndoCommand
class CScaleNodeCommand : public IUndoCommand
{
struct SNodeScale
{
@ -29,6 +28,7 @@ public:
bool mergeWith(const QUndoCommand *other);
void undo();
void redo();
bool AffectsCleanState() const { return true; }
static CScaleNodeCommand* End();
};

View File

@ -2,7 +2,7 @@
#include <Core/Scene/CSceneIterator.h>
CSelectAllCommand::CSelectAllCommand(INodeEditor *pEditor, QList<CSceneNode *> &rSelection, CScene *pScene, FNodeFlags NodeFlags)
: QUndoCommand("Select All")
: IUndoCommand("Select All")
, mpEditor(pEditor)
, mOldSelection(rSelection)
, mpSelection(&rSelection)

View File

@ -1,12 +1,11 @@
#ifndef CSELECTALLCOMMAND_H
#define CSELECTALLCOMMAND_H
#include "IUndoCommand.h"
#include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h>
#include <QUndoCommand>
class CSelectAllCommand : public QUndoCommand
class CSelectAllCommand : public IUndoCommand
{
INodeEditor *mpEditor;
QList<CSceneNode*> mOldSelection;
@ -18,6 +17,7 @@ public:
~CSelectAllCommand();
void undo();
void redo();
bool AffectsCleanState() const { return false; }
};
#endif // CSELECTALLCOMMAND_H

View File

@ -2,7 +2,7 @@
#include "Editor/INodeEditor.h"
CSelectNodeCommand::CSelectNodeCommand(INodeEditor *pEditor, CSceneNode *pNode, QList<CSceneNode*>& selection)
: QUndoCommand("Select"),
: IUndoCommand("Select"),
mpEditor(pEditor),
mpNode(pNode),
mpSelection(&selection)

View File

@ -1,12 +1,11 @@
#ifndef CSELECTNODECOMMAND_H
#define CSELECTNODECOMMAND_H
#include "IUndoCommand.h"
#include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h>
#include <QUndoCommand>
class CSelectNodeCommand : public QUndoCommand
class CSelectNodeCommand : public IUndoCommand
{
INodeEditor *mpEditor;
CSceneNode *mpNode;
@ -15,6 +14,7 @@ public:
CSelectNodeCommand(INodeEditor *pEditor, CSceneNode *pNode, QList<CSceneNode*>& selection);
void undo();
void redo();
bool AffectsCleanState() const { return false; }
};
#endif // CSELECTNODECOMMAND_H

View File

@ -3,14 +3,14 @@
#include "Editor/INodeEditor.h"
CTranslateNodeCommand::CTranslateNodeCommand()
: QUndoCommand("Translate"),
: IUndoCommand("Translate"),
mpEditor(nullptr),
mCommandEnded(false)
{
}
CTranslateNodeCommand::CTranslateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& delta, ETransformSpace transformSpace)
: QUndoCommand("Translate"),
: IUndoCommand("Translate"),
mpEditor(pEditor),
mCommandEnded(false)
{

View File

@ -1,13 +1,12 @@
#ifndef CTRANSLATENODECOMMAND_H
#define CTRANSLATENODECOMMAND_H
#include "IUndoCommand.h"
#include <Core/Scene/CSceneNode.h>
#include "Editor/INodeEditor.h"
#include <QUndoCommand>
#include <QList>
class CTranslateNodeCommand : public QUndoCommand
class CTranslateNodeCommand : public IUndoCommand
{
struct SNodeTranslate
{
@ -27,6 +26,7 @@ public:
bool mergeWith(const QUndoCommand *other);
void undo();
void redo();
bool AffectsCleanState() const { return true; }
static CTranslateNodeCommand* End();
};

View File

@ -0,0 +1,19 @@
#ifndef IUNDOCOMMAND
#define IUNDOCOMMAND
#include <QUndoCommand>
class IUndoCommand : public QUndoCommand
{
public:
IUndoCommand(QUndoCommand *pParent = 0)
: QUndoCommand(pParent) {}
IUndoCommand(const QString& rkText, QUndoCommand *pParent = 0)
: QUndoCommand(rkText, pParent) {}
virtual bool AffectsCleanState() const = 0;
};
#endif // IUNDOCOMMAND

View File

@ -77,6 +77,9 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
connect(ui->TransformSpinBox, SIGNAL(ValueChanged(CVector3f)), this, SLOT(OnTransformSpinBoxModified(CVector3f)));
connect(ui->TransformSpinBox, SIGNAL(EditingDone(CVector3f)), this, SLOT(OnTransformSpinBoxEdited(CVector3f)));
connect(ui->CamSpeedSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnCameraSpeedChange(double)));
connect(&mUndoStack, SIGNAL(indexChanged(int)), this, SLOT(OnUndoStackIndexChanged()));
connect(ui->ActionSave, SIGNAL(triggered()), this, SLOT(Save()));
}
CWorldEditor::~CWorldEditor()
@ -84,10 +87,33 @@ CWorldEditor::~CWorldEditor()
delete ui;
}
void CWorldEditor::closeEvent(QCloseEvent *)
void CWorldEditor::closeEvent(QCloseEvent *pEvent)
{
bool ShouldClose = true;
if (isWindowModified())
{
int Result = QMessageBox::warning(this, "Save", "You have unsaved changes. Save?", QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel);
if (Result == QMessageBox::Yes)
ShouldClose = Save();
else if (Result == QMessageBox::No)
ShouldClose = true;
else if (Result == QMessageBox::Cancel)
ShouldClose = false;
}
if (ShouldClose)
{
if (mpPoiDialog)
mpPoiDialog->close();
}
else
{
pEvent->ignore();
}
}
bool CWorldEditor::eventFilter(QObject * /*pObj*/, QEvent * /*pEvent*/)
@ -95,7 +121,7 @@ bool CWorldEditor::eventFilter(QObject * /*pObj*/, QEvent * /*pEvent*/)
return false;
}
void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea)
void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea, u32 AreaIndex)
{
ExitPickMode();
ui->MainViewport->ResetHover();
@ -153,6 +179,18 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea)
// Set up sidebar tabs
CMasterTemplate *pMaster = CMasterTemplate::GetMasterForGame(mpArea->Version());
ui->InstancesTabContents->SetMaster(pMaster);
// Set window title
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 (AreaName.IsEmpty())
AreaName = "[Untitled Area]";
setWindowTitle(QString("Prime World Editor - %1 - %2[*]").arg(TO_QSTRING(WorldName)).arg(TO_QSTRING(AreaName)));
}
CGameArea* CWorldEditor::ActiveArea()
@ -160,7 +198,26 @@ CGameArea* CWorldEditor::ActiveArea()
return mpArea;
}
// ************ PROTECTED SLOTS ************
// ************ PUBLIC SLOTS ************
bool CWorldEditor::Save()
{
TString Out = mpArea->FullSource();
CFileOutStream MREA(Out.ToStdString(), IOUtil::eBigEndian);
if (MREA.IsValid())
{
CAreaCooker::WriteCookedArea(mpArea, MREA);
mUndoStack.setClean();
setWindowModified(false);
return true;
}
else
{
QMessageBox::warning(this, "Error", "Unable to save error; couldn't open output file " + TO_QSTRING(Out));
return false;
}
}
void CWorldEditor::UpdateStatusBar()
{
// Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag.
@ -281,6 +338,55 @@ void CWorldEditor::GizmoModeChanged(CGizmo::EGizmoMode mode)
}
// ************ PRIVATE SLOTS ************
void CWorldEditor::OnUndoStackIndexChanged()
{
// Check the commands that have been executed on the undo stack and find out whether any of them affect the clean state.
// This is to prevent commands like select/deselect from altering the clean state.
int CurrentIndex = mUndoStack.index();
int CleanIndex = mUndoStack.cleanIndex();
if (CurrentIndex == CleanIndex)
setWindowModified(false);
else
{
bool IsClean = true;
int LowIndex = (CurrentIndex > CleanIndex ? CleanIndex + 1 : CurrentIndex);
int HighIndex = (CurrentIndex > CleanIndex ? CurrentIndex - 1 : CleanIndex);
for (int iIdx = LowIndex; iIdx <= HighIndex; iIdx++)
{
const QUndoCommand *pkQCmd = mUndoStack.command(iIdx);
if (pkQCmd->childCount() > 0)
{
for (int iChild = 0; iChild < pkQCmd->childCount(); iChild++)
{
const IUndoCommand *pkCmd = static_cast<const IUndoCommand*>(pkQCmd->child(iChild));
if (pkCmd->AffectsCleanState())
{
IsClean = false;
break;
}
}
}
else
{
const IUndoCommand *pkCmd = static_cast<const IUndoCommand*>(pkQCmd);
if (pkCmd->AffectsCleanState())
IsClean = false;
}
if (!IsClean) break;
}
setWindowModified(!IsClean);
}
}
void CWorldEditor::OnPickModeEnter(QCursor Cursor)
{
ui->MainViewport->SetCursorState(Cursor);
@ -530,11 +636,3 @@ void CWorldEditor::on_ActionEditPoiToWorldMap_triggered()
mpPoiDialog->show();
}
}
void CWorldEditor::on_ActionSave_triggered()
{
TString Out = mpArea->FullSource();
CFileOutStream MREA(Out.ToStdString(), IOUtil::eBigEndian);
CAreaCooker::WriteCookedArea(mpArea, MREA);
QMessageBox::information(this, "Success", "Successfully saved area to " + TO_QSTRING(Out));
}

View File

@ -40,12 +40,14 @@ class CWorldEditor : public INodeEditor
public:
explicit CWorldEditor(QWidget *parent = 0);
~CWorldEditor();
void closeEvent(QCloseEvent *);
void closeEvent(QCloseEvent *pEvent);
bool eventFilter(QObject *pObj, QEvent *pEvent);
void SetArea(CWorld *pWorld, CGameArea *pArea);
void SetArea(CWorld *pWorld, CGameArea *pArea, u32 AreaIndex);
CGameArea* ActiveArea();
public slots:
bool Save();
void UpdateStatusBar();
void UpdateGizmoUI();
void UpdateSelectionUI();
@ -55,6 +57,7 @@ protected:
void GizmoModeChanged(CGizmo::EGizmoMode mode);
private slots:
void OnUndoStackIndexChanged();
void OnPickModeEnter(QCursor Cursor);
void OnPickModeExit();
void RefreshViewport();
@ -85,7 +88,6 @@ private slots:
void on_ActionSelectAll_triggered();
void on_ActionInvertSelection_triggered();
void on_ActionEditPoiToWorldMap_triggered();
void on_ActionSave_triggered();
};
#endif // CWORLDEDITOR_H

View File

@ -9,7 +9,7 @@
<property ID="0x04" name="Unknown 1" type="vector3f"/>
<property ID="0x05" name="Unknown 2" type="long"/>
<property ID="0x06" name="Unknown 3" type="bool"/>
<property ID="0x07" name="Unknown 4" type="bool"/>
<property ID="0x07" name="Display Fluid Surface" type="bool"/>
<property ID="0x08" name="Texture 1" type="file" extensions="TXTR"/>
<property ID="0x09" name="Texture 2" type="file" extensions="TXTR"/>
<property ID="0x0A" name="Texture 3" type="file" extensions="TXTR"/>
@ -20,7 +20,7 @@
<property ID="0x0F" name="Unknown 6" type="float"/>
<property ID="0x10" name="Unknown 7" type="float"/>
<property ID="0x11" name="Unknown 8" type="float"/>
<property ID="0x12" name="Unknown 9" type="bool"/>
<property ID="0x12" name="Active" type="bool"/>
<property ID="0x13" name="Unknown 10" type="long"/>
<property ID="0x14" name="Unknown 11" type="bool"/>
<property ID="0x15" name="Unknown 12" type="float"/>
@ -55,7 +55,9 @@
<property ID="0x1E" name="Unknown 37" type="float"/>
<property ID="0x1F" name="Unknown 38" type="color"/>
<property ID="0x20" name="Unknown 39" type="color"/>
<property ID="0x21" name="Particle 1" type="file" extensions="PART"/>
<property ID="0x21" name="Enter Particle" type="file" extensions="PART">
<description>This particle plays when an actor/projectile enters the water. It also plays when the morph ball is rolling in it at surface level.</description>
</property>
<property ID="0x22" name="Particle 2" type="file" extensions="PART"/>
<property ID="0x23" name="Particle 3" type="file" extensions="PART"/>
<property ID="0x24" name="Particle 4" type="file" extensions="PART"/>
@ -73,10 +75,10 @@
<property ID="0x30" name="Unknown 45" type="float"/>
<property ID="0x31" name="Unknown 46" type="float"/>
<property ID="0x32" name="Unknown 47" type="float"/>
<property ID="0x33" name="Unknown 48" type="float"/>
<property ID="0x34" name="Unknown 49" type="float"/>
<property ID="0x35" name="Unknown 50" type="color"/>
<property ID="0x36" name="Texture 7" type="file" extensions="TXTR"/>
<property ID="0x33" name="Heat Wave Height" type="float"/>
<property ID="0x34" name="Heat Wave Speed" type="float"/>
<property ID="0x35" name="Heat Wave Color" type="color"/>
<property ID="0x36" name="Lightmap Texture" type="file" extensions="TXTR"/>
<property ID="0x37" name="Unknown 51" type="float"/>
<property ID="0x38" name="Unknown 52" type="float"/>
<property ID="0x39" name="Unknown 53" type="float"/>
@ -91,6 +93,7 @@
<property name="InstanceName" ID="0x00"/>
<property name="Position" ID="0x01"/>
<property name="Scale" ID="0x02"/>
<property name="Active" ID="0x09"/>
</properties>
<assets/>
<rotation_type>disabled</rotation_type>