Reimplemented array resizing
This commit is contained in:
parent
641cf81dd8
commit
a90f1d0441
|
@ -199,7 +199,8 @@ HEADERS += \
|
||||||
CGeneratePropertyNamesDialog.h \
|
CGeneratePropertyNamesDialog.h \
|
||||||
CProgressBarNotifier.h \
|
CProgressBarNotifier.h \
|
||||||
Widgets/CCheckableTreeWidgetItem.h \
|
Widgets/CCheckableTreeWidgetItem.h \
|
||||||
Widgets/CCheckableTreeWidget.h
|
Widgets/CCheckableTreeWidget.h \
|
||||||
|
Undo/IEditPropertyCommand.h
|
||||||
|
|
||||||
# Source Files
|
# Source Files
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
@ -237,8 +238,6 @@ SOURCES += \
|
||||||
PropertyEdit/CPropertyDelegate.cpp \
|
PropertyEdit/CPropertyDelegate.cpp \
|
||||||
PropertyEdit/CPropertyView.cpp \
|
PropertyEdit/CPropertyView.cpp \
|
||||||
WorldEditor/CInstancesModel.cpp \
|
WorldEditor/CInstancesModel.cpp \
|
||||||
Undo/CEditScriptPropertyCommand.cpp \
|
|
||||||
Undo/CResizeScriptArrayCommand.cpp \
|
|
||||||
WorldEditor/WEditorProperties.cpp \
|
WorldEditor/WEditorProperties.cpp \
|
||||||
Undo/CChangeLayerCommand.cpp \
|
Undo/CChangeLayerCommand.cpp \
|
||||||
WorldEditor/CTemplateEditDialog.cpp \
|
WorldEditor/CTemplateEditDialog.cpp \
|
||||||
|
@ -275,7 +274,8 @@ SOURCES += \
|
||||||
ResourceBrowser/CVirtualDirectoryModel.cpp \
|
ResourceBrowser/CVirtualDirectoryModel.cpp \
|
||||||
ResourceBrowser/CVirtualDirectoryTreeView.cpp \
|
ResourceBrowser/CVirtualDirectoryTreeView.cpp \
|
||||||
CPropertyNameValidator.cpp \
|
CPropertyNameValidator.cpp \
|
||||||
CGeneratePropertyNamesDialog.cpp
|
CGeneratePropertyNamesDialog.cpp \
|
||||||
|
Undo/IEditPropertyCommand.cpp
|
||||||
|
|
||||||
# UI Files
|
# UI Files
|
||||||
FORMS += \
|
FORMS += \
|
||||||
|
|
|
@ -365,7 +365,7 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
||||||
if (Type != EPropertyTypeNew::Array)
|
if (Type != EPropertyTypeNew::Array)
|
||||||
{
|
{
|
||||||
// TODO: support this for non script object properties
|
// TODO: support this for non script object properties
|
||||||
pCommand = new CEditScriptPropertyCommand(mpEditor, mpModel->GetScriptObject(), pProp);
|
pCommand = new CEditScriptPropertyCommand(mpEditor, rkIndex, mpModel);
|
||||||
pCommand->SaveOldData();
|
pCommand->SaveOldData();
|
||||||
|
|
||||||
// Handle sub-properties of flags and animation sets
|
// Handle sub-properties of flags and animation sets
|
||||||
|
@ -478,18 +478,22 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
||||||
// Array
|
// Array
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//FIXME
|
pCommand = new CResizeScriptArrayCommand(mpEditor, rkIndex, mpModel);
|
||||||
/*
|
pCommand->SaveOldData();
|
||||||
|
|
||||||
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
||||||
CArrayProperty* pArray = static_cast<CArrayProperty*>(pProp);
|
CArrayProperty* pArray = static_cast<CArrayProperty*>(pProp);
|
||||||
|
int OldCount = pArray->ArrayCount(pData);
|
||||||
int NewCount = pSpinBox->value();
|
int NewCount = pSpinBox->value();
|
||||||
|
|
||||||
if (pArray->Count() != NewCount)
|
if (OldCount != NewCount)
|
||||||
{
|
{
|
||||||
CResizeScriptArrayCommand *pCmd = new CResizeScriptArrayCommand(pProp, mpEditor, mpModel, NewCount);
|
mpModel->ArrayAboutToBeResized(rkIndex, NewCount);
|
||||||
mpEditor->UndoStack()->push(pCmd);
|
pArray->Resize(pData, NewCount);
|
||||||
|
mpModel->ArrayResized(rkIndex, OldCount);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
pCommand->SaveNewData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,25 @@ CPropertyModel::CPropertyModel(QObject *pParent /*= 0*/)
|
||||||
, mpPropertyData(nullptr)
|
, mpPropertyData(nullptr)
|
||||||
, mBoldModifiedProperties(true)
|
, mBoldModifiedProperties(true)
|
||||||
, mShowNameValidity(false)
|
, mShowNameValidity(false)
|
||||||
|
, mFirstUnusedID(-1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int CPropertyModel::RecursiveBuildArrays(IPropertyNew* pProperty, int ParentID)
|
int CPropertyModel::RecursiveBuildArrays(IPropertyNew* pProperty, int ParentID)
|
||||||
{
|
{
|
||||||
int MyID = mProperties.size();
|
// Insert into an unused slot if one exists. Otherwise, append to the end of the array.
|
||||||
|
int MyID = -1;
|
||||||
|
|
||||||
|
if (mFirstUnusedID >= 0)
|
||||||
|
{
|
||||||
|
MyID = mFirstUnusedID;
|
||||||
|
mFirstUnusedID = mProperties[MyID].ParentID; // on unused slots ParentID stores the ID of the next unused slot
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MyID = mProperties.size();
|
||||||
mProperties << SProperty();
|
mProperties << SProperty();
|
||||||
|
}
|
||||||
|
|
||||||
mProperties[MyID].pProperty = pProperty;
|
mProperties[MyID].pProperty = pProperty;
|
||||||
mProperties[MyID].ParentID = ParentID;
|
mProperties[MyID].ParentID = ParentID;
|
||||||
|
@ -70,6 +82,7 @@ void CPropertyModel::ConfigureIntrinsic(CGameProject* pProject, IPropertyNew* pR
|
||||||
|
|
||||||
mProperties.clear();
|
mProperties.clear();
|
||||||
mPropertyToIDMap.clear();
|
mPropertyToIDMap.clear();
|
||||||
|
mFirstUnusedID = -1;
|
||||||
|
|
||||||
if (pRootProperty)
|
if (pRootProperty)
|
||||||
RecursiveBuildArrays(pRootProperty, -1);
|
RecursiveBuildArrays(pRootProperty, -1);
|
||||||
|
@ -532,13 +545,13 @@ void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex)
|
||||||
|
|
||||||
void CPropertyModel::ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize)
|
void CPropertyModel::ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize)
|
||||||
{
|
{
|
||||||
//FIXME
|
QModelIndex Index = rkIndex.sibling(rkIndex.row(), 0);
|
||||||
/*QModelIndex Index = rkIndex.sibling(rkIndex.row(), 0);
|
IPropertyNew* pProperty = PropertyForIndex(Index, false);
|
||||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(Index, false));
|
CArrayProperty* pArray = TPropCast<CArrayProperty>(pProperty);
|
||||||
|
ASSERT(pArray);
|
||||||
|
|
||||||
if (pArray && pArray->Type() == eArrayProperty)
|
void* pArrayData = DataPointerForIndex(Index);
|
||||||
{
|
u32 OldSize = pArray->ArrayCount(pArrayData);
|
||||||
u32 OldSize = pArray->Count();
|
|
||||||
|
|
||||||
if (NewSize != OldSize)
|
if (NewSize != OldSize)
|
||||||
{
|
{
|
||||||
|
@ -547,22 +560,65 @@ void CPropertyModel::ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSi
|
||||||
else
|
else
|
||||||
beginRemoveRows(Index, NewSize, OldSize - 1);
|
beginRemoveRows(Index, NewSize, OldSize - 1);
|
||||||
}
|
}
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPropertyModel::ArrayResized(const QModelIndex& rkIndex, u32 OldSize)
|
void CPropertyModel::ArrayResized(const QModelIndex& rkIndex, u32 OldSize)
|
||||||
{
|
{
|
||||||
//FIXME
|
QModelIndex Index = rkIndex.sibling(rkIndex.row(), 0);
|
||||||
/*CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(rkIndex, false));
|
IPropertyNew* pProperty = PropertyForIndex(Index, false);
|
||||||
u32 NewSize = pArray->Count();
|
CArrayProperty* pArray = TPropCast<CArrayProperty>(pProperty);
|
||||||
|
ASSERT(pArray);
|
||||||
|
|
||||||
|
void* pArrayData = DataPointerForIndex(Index);
|
||||||
|
u32 NewSize = pArray->ArrayCount(pArrayData);
|
||||||
|
|
||||||
if (NewSize != OldSize)
|
if (NewSize != OldSize)
|
||||||
{
|
{
|
||||||
if (pArray->Count() > OldSize)
|
int ID = Index.internalId();
|
||||||
|
|
||||||
|
if (NewSize > OldSize)
|
||||||
|
{
|
||||||
|
// add new elements
|
||||||
|
void* pOldData = mpPropertyData;
|
||||||
|
|
||||||
|
for (u32 ElementIdx = OldSize; ElementIdx < NewSize; ElementIdx++)
|
||||||
|
{
|
||||||
|
mpPropertyData = pArray->ItemPointer(pArrayData, ElementIdx);
|
||||||
|
int NewChildID = RecursiveBuildArrays( pArray->ItemArchetype(), ID );
|
||||||
|
mProperties[ID].ChildIDs.push_back(NewChildID);
|
||||||
|
}
|
||||||
|
|
||||||
|
mpPropertyData = pOldData;
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
// remove old elements
|
||||||
|
for (u32 ElementIdx = NewSize; ElementIdx < OldSize; ElementIdx++)
|
||||||
|
{
|
||||||
|
int ChildID = mProperties[ID].ChildIDs[ElementIdx];
|
||||||
|
ClearSlot(ChildID);
|
||||||
|
}
|
||||||
|
|
||||||
|
mProperties[ID].ChildIDs.resize(NewSize);
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
}*/
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CPropertyModel::ClearSlot(int ID)
|
||||||
|
{
|
||||||
|
for (int ChildIdx = 0; ChildIdx < mProperties[ID].ChildIDs.size(); ChildIdx++)
|
||||||
|
{
|
||||||
|
ClearSlot(mProperties[ID].ChildIDs[ChildIdx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mProperties[ID].ChildIDs.clear();
|
||||||
|
mProperties[ID].Index = QModelIndex();
|
||||||
|
mProperties[ID].ParentID = mFirstUnusedID;
|
||||||
|
mProperties[ID].pProperty = nullptr;
|
||||||
|
mFirstUnusedID = ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPropertyModel::SetShowPropertyNameValidity(bool Enable)
|
void CPropertyModel::SetShowPropertyNameValidity(bool Enable)
|
||||||
|
|
|
@ -18,6 +18,7 @@ class CPropertyModel : public QAbstractItemModel
|
||||||
};
|
};
|
||||||
QVector<SProperty> mProperties;
|
QVector<SProperty> mProperties;
|
||||||
QMap<IPropertyNew*, int> mPropertyToIDMap;
|
QMap<IPropertyNew*, int> mPropertyToIDMap;
|
||||||
|
int mFirstUnusedID;
|
||||||
|
|
||||||
CGameProject* mpProject;
|
CGameProject* mpProject;
|
||||||
CScriptObject* mpObject; // may be null
|
CScriptObject* mpObject; // may be null
|
||||||
|
@ -49,6 +50,7 @@ public:
|
||||||
void ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize);
|
void ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize);
|
||||||
void ArrayResized(const QModelIndex& rkIndex, u32 OldSize);
|
void ArrayResized(const QModelIndex& rkIndex, u32 OldSize);
|
||||||
void ResizeArray(const QModelIndex& rkIndex, u32 NewSize);
|
void ResizeArray(const QModelIndex& rkIndex, u32 NewSize);
|
||||||
|
void ClearSlot(int ID);
|
||||||
|
|
||||||
void SetShowPropertyNameValidity(bool Enable);
|
void SetShowPropertyNameValidity(bool Enable);
|
||||||
|
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
#include "CEditScriptPropertyCommand.h"
|
|
||||||
#include "EUndoCommand.h"
|
|
||||||
|
|
||||||
/*CEditScriptPropertyCommand::CEditScriptPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, IPropertyValue *pOldValue, bool IsDone, const QString& rkCommandName /*= "Edit Property")
|
|
||||||
: IUndoCommand(rkCommandName)
|
|
||||||
, mpProp(pProp)
|
|
||||||
, mpEditor(pEditor)
|
|
||||||
, mCommandEnded(IsDone)
|
|
||||||
{
|
|
||||||
mpOldValue = pOldValue;
|
|
||||||
mpNewValue = pProp->RawValue()->Clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
CEditScriptPropertyCommand::~CEditScriptPropertyCommand()
|
|
||||||
{
|
|
||||||
delete mpOldValue;
|
|
||||||
delete mpNewValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CEditScriptPropertyCommand::id() const
|
|
||||||
{
|
|
||||||
return eEditScriptPropertyCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CEditScriptPropertyCommand::mergeWith(const QUndoCommand *pkOther)
|
|
||||||
{
|
|
||||||
if (!mCommandEnded && pkOther->id() == eEditScriptPropertyCmd)
|
|
||||||
{
|
|
||||||
const CEditScriptPropertyCommand *pkCmd = static_cast<const CEditScriptPropertyCommand*>(pkOther);
|
|
||||||
|
|
||||||
if (pkCmd->mpProp == mpProp)
|
|
||||||
{
|
|
||||||
mpNewValue->Copy(pkCmd->mpNewValue);
|
|
||||||
mCommandEnded = pkCmd->mCommandEnded;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CEditScriptPropertyCommand::undo()
|
|
||||||
{
|
|
||||||
IProperty *pProp = *mpProp;
|
|
||||||
pProp->RawValue()->Copy(mpOldValue);
|
|
||||||
mpEditor->OnPropertyModified(pProp);
|
|
||||||
mCommandEnded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CEditScriptPropertyCommand::redo()
|
|
||||||
{
|
|
||||||
IProperty *pProp = *mpProp;
|
|
||||||
pProp->RawValue()->Copy(mpNewValue);
|
|
||||||
mpEditor->OnPropertyModified(pProp);
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -1,167 +1,29 @@
|
||||||
#ifndef CEDITSCRIPTPROPERTYCOMMAND_H
|
#ifndef CEDITSCRIPTPROPERTYCOMMAND_H
|
||||||
#define CEDITSCRIPTPROPERTYCOMMAND_H
|
#define CEDITSCRIPTPROPERTYCOMMAND_H
|
||||||
|
|
||||||
#include "IUndoCommand.h"
|
#include "IEditPropertyCommand.h"
|
||||||
#include "ObjReferences.h"
|
#include "ObjReferences.h"
|
||||||
#include "EUndoCommand.h"
|
|
||||||
#include "Editor/PropertyEdit/CPropertyModel.h"
|
|
||||||
#include "Editor/WorldEditor/CWorldEditor.h"
|
#include "Editor/WorldEditor/CWorldEditor.h"
|
||||||
|
|
||||||
class IEditPropertyCommand : public IUndoCommand
|
|
||||||
{
|
|
||||||
std::vector<char> mOldData;
|
|
||||||
std::vector<char> mNewData;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
IPropertyNew* mpProperty;
|
|
||||||
bool mCommandEnded;
|
|
||||||
bool mSavedOldData;
|
|
||||||
bool mSavedNewData;
|
|
||||||
|
|
||||||
/** Save the current state of the object properties to the given data buffer */
|
|
||||||
void SaveObjectStateToArray(std::vector<char>& rVector)
|
|
||||||
{
|
|
||||||
CVectorOutStream MemStream(&rVector, IOUtil::kSystemEndianness);
|
|
||||||
CBasicBinaryWriter Writer(&MemStream, CSerialVersion(IArchive::skCurrentArchiveVersion, 0, mpProperty->Game()));
|
|
||||||
|
|
||||||
std::vector<void*> DataPointers;
|
|
||||||
GetObjectDataPointers(DataPointers);
|
|
||||||
|
|
||||||
for (int PtrIdx = 0; PtrIdx < DataPointers.size(); PtrIdx++)
|
|
||||||
{
|
|
||||||
void* pData = DataPointers[PtrIdx];
|
|
||||||
mpProperty->SerializeValue(pData, Writer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Restore the state of the object properties from the given data buffer */
|
|
||||||
void RestoreObjectStateFromArray(std::vector<char>& rArray)
|
|
||||||
{
|
|
||||||
CBasicBinaryReader Reader(rArray.data(), rArray.size(), CSerialVersion(IArchive::skCurrentArchiveVersion, 0, mpProperty->Game()));
|
|
||||||
|
|
||||||
std::vector<void*> DataPointers;
|
|
||||||
GetObjectDataPointers(DataPointers);
|
|
||||||
|
|
||||||
for (int PtrIdx = 0; PtrIdx < DataPointers.size(); PtrIdx++)
|
|
||||||
{
|
|
||||||
void* pData = DataPointers[PtrIdx];
|
|
||||||
mpProperty->SerializeValue(pData, Reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
IEditPropertyCommand(IPropertyNew* pProperty, const QString& rkCommandName = "Edit Property")
|
|
||||||
: IUndoCommand(rkCommandName)
|
|
||||||
, mpProperty(pProperty)
|
|
||||||
, mSavedOldData(false)
|
|
||||||
, mSavedNewData(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void SaveOldData()
|
|
||||||
{
|
|
||||||
SaveObjectStateToArray(mOldData);
|
|
||||||
mSavedOldData = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveNewData()
|
|
||||||
{
|
|
||||||
SaveObjectStateToArray(mNewData);
|
|
||||||
mSavedNewData = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsNewDataDifferent()
|
|
||||||
{
|
|
||||||
if (mOldData.size() != mNewData.size()) return false;
|
|
||||||
return memcmp(mOldData.data(), mNewData.data(), mNewData.size()) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetEditComplete(bool IsComplete)
|
|
||||||
{
|
|
||||||
mCommandEnded = IsComplete;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Interface */
|
|
||||||
virtual void GetObjectDataPointers(std::vector<void*>& rOutPointers) const = 0;
|
|
||||||
|
|
||||||
/** IUndoCommand/QUndoCommand interface */
|
|
||||||
int id() const
|
|
||||||
{
|
|
||||||
return eEditScriptPropertyCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mergeWith(const QUndoCommand *pkOther)
|
|
||||||
{
|
|
||||||
if (!mCommandEnded)
|
|
||||||
{
|
|
||||||
const IEditPropertyCommand* pkCmd = dynamic_cast<const IEditPropertyCommand*>(pkOther);
|
|
||||||
|
|
||||||
if (pkCmd && pkCmd->mpProperty == mpProperty)
|
|
||||||
{
|
|
||||||
std::vector<void*> MyPointers;
|
|
||||||
GetObjectDataPointers(MyPointers);
|
|
||||||
|
|
||||||
std::vector<void*> TheirPointers;
|
|
||||||
pkCmd->GetObjectDataPointers(TheirPointers);
|
|
||||||
|
|
||||||
if (TheirPointers.size() == MyPointers.size())
|
|
||||||
{
|
|
||||||
for (int PtrIdx = 0; PtrIdx < MyPointers.size(); PtrIdx++)
|
|
||||||
{
|
|
||||||
if (MyPointers[PtrIdx] != TheirPointers[PtrIdx])
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match
|
|
||||||
mNewData = pkCmd->mNewData;
|
|
||||||
mCommandEnded = pkCmd->mCommandEnded;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void undo()
|
|
||||||
{
|
|
||||||
ASSERT(mSavedOldData && mSavedNewData);
|
|
||||||
RestoreObjectStateFromArray(mOldData);
|
|
||||||
mCommandEnded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void redo()
|
|
||||||
{
|
|
||||||
ASSERT(mSavedOldData && mSavedNewData);
|
|
||||||
RestoreObjectStateFromArray(mNewData);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AffectsCleanState() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CEditScriptPropertyCommand : public IEditPropertyCommand
|
class CEditScriptPropertyCommand : public IEditPropertyCommand
|
||||||
{
|
{
|
||||||
std::vector<CInstancePtr> mInstances;
|
std::vector<CInstancePtr> mInstances;
|
||||||
CWorldEditor* mpEditor;
|
CWorldEditor* mpEditor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CEditScriptPropertyCommand(CWorldEditor* pEditor, CScriptObject* pInstance, IPropertyNew* pProperty, const QString& rkCommandName = "Edit Property")
|
CEditScriptPropertyCommand(CWorldEditor* pEditor, const QModelIndex& rkIndex, CPropertyModel* pInModel, const QString& rkCommandName = "Edit Property")
|
||||||
: IEditPropertyCommand(pProperty, rkCommandName)
|
: IEditPropertyCommand(rkIndex, pInModel, rkCommandName)
|
||||||
, mpEditor(pEditor)
|
, mpEditor(pEditor)
|
||||||
{
|
{
|
||||||
mInstances.push_back( CInstancePtr(pInstance) );
|
mInstances.push_back( CInstancePtr(pInModel->GetScriptObject()) );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void GetObjectDataPointers(std::vector<void*>& rOutPointers) const override
|
virtual void GetObjectDataPointers(std::vector<void*>& rOutPointers) const override
|
||||||
{
|
{
|
||||||
rOutPointers.resize(mInstances.size());
|
rOutPointers.resize(mInstances.size());
|
||||||
|
|
||||||
for (int InstanceIdx = 0; InstanceIdx < mInstances.size(); InstanceIdx++)
|
//@todo support multiple objects
|
||||||
{
|
rOutPointers[0] = mpModel->DataPointerForIndex(mIndex);
|
||||||
rOutPointers[InstanceIdx] = mInstances[InstanceIdx]->PropertyData();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void undo() override
|
virtual void undo() override
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
#include "CResizeScriptArrayCommand.h"
|
|
||||||
/*
|
|
||||||
CResizeScriptArrayCommand::CResizeScriptArrayCommand(IPropertyNew *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize)
|
|
||||||
: IUndoCommand("Edit Property")
|
|
||||||
, mpEditor(pEditor)
|
|
||||||
, mpArray(pProp)
|
|
||||||
, mpModel(pModel)
|
|
||||||
, mOldSize(static_cast<CArrayProperty*>(pProp)->Count())
|
|
||||||
, mNewSize(NewSize)
|
|
||||||
{
|
|
||||||
mNewSizeLarger = mNewSize > mOldSize;
|
|
||||||
|
|
||||||
if (!mNewSizeLarger)
|
|
||||||
{
|
|
||||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
|
|
||||||
|
|
||||||
for (int iSub = mNewSize; iSub < mOldSize; iSub++)
|
|
||||||
{
|
|
||||||
mDeletedProperties << pArray->PropertyByIndex(iSub)->Clone(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CResizeScriptArrayCommand::~CResizeScriptArrayCommand()
|
|
||||||
{
|
|
||||||
foreach (IPropertyNew *pProp, mDeletedProperties)
|
|
||||||
delete pProp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CResizeScriptArrayCommand::undo()
|
|
||||||
{
|
|
||||||
if (mNewSize != mOldSize)
|
|
||||||
{
|
|
||||||
// Update parents
|
|
||||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(*mpArray);
|
|
||||||
|
|
||||||
foreach (IProperty *pProp, mDeletedProperties)
|
|
||||||
pProp->SetParent(pArray);
|
|
||||||
|
|
||||||
// Resize array
|
|
||||||
QModelIndex Index = mpModel->IndexForProperty(pArray);
|
|
||||||
mpModel->ArrayAboutToBeResized(Index, (u32) mOldSize);
|
|
||||||
pArray->Resize(mOldSize);
|
|
||||||
|
|
||||||
if (!mNewSizeLarger)
|
|
||||||
{
|
|
||||||
int NumNewElements = mOldSize - mNewSize;
|
|
||||||
|
|
||||||
for (int iSub = 0; iSub < NumNewElements; iSub++)
|
|
||||||
{
|
|
||||||
u32 Idx = iSub + mNewSize;
|
|
||||||
pArray->PropertyByIndex(Idx)->Copy(mDeletedProperties[iSub]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mpModel->ArrayResized(Index, (u32) mNewSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CResizeScriptArrayCommand::redo()
|
|
||||||
{
|
|
||||||
// Whether we're increasing or decreasing in size, there's no need to restore deleted properties on redo.
|
|
||||||
if (mNewSize != mOldSize)
|
|
||||||
{
|
|
||||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(*mpArray);
|
|
||||||
QModelIndex Index = mpModel->IndexForProperty(pArray);
|
|
||||||
mpModel->ArrayAboutToBeResized(Index, (u32) mNewSize);
|
|
||||||
pArray->Resize(mNewSize);
|
|
||||||
mpModel->ArrayResized(Index, (u32) mOldSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -1,31 +1,50 @@
|
||||||
#ifndef CRESIZESCRIPTARRAYCOMMAND_H
|
#ifndef CRESIZESCRIPTARRAYCOMMAND_H
|
||||||
#define CRESIZESCRIPTARRAYCOMMAND_H
|
#define CRESIZESCRIPTARRAYCOMMAND_H
|
||||||
|
|
||||||
#include "IUndoCommand.h"
|
#include "CEditScriptPropertyCommand.h"
|
||||||
#include "ObjReferences.h"
|
|
||||||
#include "Editor/PropertyEdit/CPropertyModel.h"
|
|
||||||
#include "Editor/WorldEditor/CWorldEditor.h"
|
|
||||||
#include <QUndoCommand>
|
|
||||||
|
|
||||||
// todo: make this more general... it shouldn't be relying on a CPropertyModel pointer
|
class CResizeScriptArrayCommand : public CEditScriptPropertyCommand
|
||||||
//FIXME
|
|
||||||
/*class CResizeScriptArrayCommand : public IUndoCommand
|
|
||||||
{
|
{
|
||||||
CWorldEditor* mpEditor;
|
|
||||||
IPropertyNew* mpArray;
|
|
||||||
QVector<IPropertyNew*> mDeletedProperties;
|
|
||||||
CPropertyModel *mpModel;
|
|
||||||
|
|
||||||
int mOldSize;
|
|
||||||
int mNewSize;
|
|
||||||
bool mNewSizeLarger;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CResizeScriptArrayCommand(IPropertyNew *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize);
|
CResizeScriptArrayCommand(CWorldEditor* pEditor, const QModelIndex& rkIndex, CPropertyModel* pInModel, const QString& rkCommandName = "Resize Array")
|
||||||
~CResizeScriptArrayCommand();
|
: CEditScriptPropertyCommand(pEditor, rkIndex, pInModel, rkCommandName)
|
||||||
void undo();
|
{}
|
||||||
void redo();
|
|
||||||
bool AffectsCleanState() const { return true; }
|
bool mergeWith(const QUndoCommand *pkOther)
|
||||||
};*/
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note in some cases undo/redo may be called when the change has already been applied outside of the undo command
|
||||||
|
// This is why we need to check the array's actual current size instead of assuming it will match one of the arrays
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
// unpleasant cast, but easiest/fastest way to access the sizes
|
||||||
|
int NewSize = *((int*)mOldData.data());
|
||||||
|
int OldSize = CurrentArrayCount();
|
||||||
|
|
||||||
|
mpModel->ArrayAboutToBeResized(mIndex, NewSize);
|
||||||
|
CEditScriptPropertyCommand::undo();
|
||||||
|
mpModel->ArrayResized(mIndex, OldSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
// unpleasant cast, but easiest/fastest way to access the sizes
|
||||||
|
int NewSize = *((int*)mNewData.data());
|
||||||
|
int OldSize = CurrentArrayCount();
|
||||||
|
|
||||||
|
mpModel->ArrayAboutToBeResized(mIndex, NewSize);
|
||||||
|
CEditScriptPropertyCommand::redo();
|
||||||
|
mpModel->ArrayResized(mIndex, OldSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CurrentArrayCount()
|
||||||
|
{
|
||||||
|
void* pData = mpModel->DataPointerForIndex(mIndex);
|
||||||
|
CArrayProperty* pArray = TPropCast<CArrayProperty>(mpProperty);
|
||||||
|
return pArray->ArrayCount(pData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif // CRESIZESCRIPTARRAYCOMMAND_H
|
#endif // CRESIZESCRIPTARRAYCOMMAND_H
|
||||||
|
|
|
@ -8,7 +8,7 @@ enum EUndoCommand
|
||||||
eTranslateNodeCmd,
|
eTranslateNodeCmd,
|
||||||
eRotateNodeCmd,
|
eRotateNodeCmd,
|
||||||
eScaleNodeCmd,
|
eScaleNodeCmd,
|
||||||
eEditScriptPropertyCmd
|
eEditPropertyCmd
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // EUNDOCOMMAND
|
#endif // EUNDOCOMMAND
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
#include "IEditPropertyCommand.h"
|
||||||
|
|
||||||
|
/** Save the current state of the object properties to the given data buffer */
|
||||||
|
void IEditPropertyCommand::SaveObjectStateToArray(std::vector<char>& rVector)
|
||||||
|
{
|
||||||
|
CVectorOutStream MemStream(&rVector, IOUtil::kSystemEndianness);
|
||||||
|
CBasicBinaryWriter Writer(&MemStream, CSerialVersion(IArchive::skCurrentArchiveVersion, 0, mpProperty->Game()));
|
||||||
|
|
||||||
|
std::vector<void*> DataPointers;
|
||||||
|
GetObjectDataPointers(DataPointers);
|
||||||
|
|
||||||
|
for (int PtrIdx = 0; PtrIdx < DataPointers.size(); PtrIdx++)
|
||||||
|
{
|
||||||
|
void* pData = DataPointers[PtrIdx];
|
||||||
|
mpProperty->SerializeValue(pData, Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Restore the state of the object properties from the given data buffer */
|
||||||
|
void IEditPropertyCommand::RestoreObjectStateFromArray(std::vector<char>& rArray)
|
||||||
|
{
|
||||||
|
CBasicBinaryReader Reader(rArray.data(), rArray.size(), CSerialVersion(IArchive::skCurrentArchiveVersion, 0, mpProperty->Game()));
|
||||||
|
|
||||||
|
std::vector<void*> DataPointers;
|
||||||
|
GetObjectDataPointers(DataPointers);
|
||||||
|
|
||||||
|
for (int PtrIdx = 0; PtrIdx < DataPointers.size(); PtrIdx++)
|
||||||
|
{
|
||||||
|
void* pData = DataPointers[PtrIdx];
|
||||||
|
mpProperty->SerializeValue(pData, Reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEditPropertyCommand::IEditPropertyCommand(
|
||||||
|
const QModelIndex& rkInIndex,
|
||||||
|
CPropertyModel* pInModel,
|
||||||
|
const QString& rkCommandName /*= "Edit Property"*/
|
||||||
|
)
|
||||||
|
: IUndoCommand(rkCommandName)
|
||||||
|
, mIndex(rkInIndex)
|
||||||
|
, mpModel(pInModel)
|
||||||
|
, mSavedOldData(false)
|
||||||
|
, mSavedNewData(false)
|
||||||
|
{
|
||||||
|
mpProperty = mpModel->PropertyForIndex(rkInIndex, true);
|
||||||
|
ASSERT(mpModel && mpProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IEditPropertyCommand::SaveOldData()
|
||||||
|
{
|
||||||
|
SaveObjectStateToArray(mOldData);
|
||||||
|
mSavedOldData = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IEditPropertyCommand::SaveNewData()
|
||||||
|
{
|
||||||
|
SaveObjectStateToArray(mNewData);
|
||||||
|
mSavedNewData = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEditPropertyCommand::IsNewDataDifferent()
|
||||||
|
{
|
||||||
|
if (mOldData.size() != mNewData.size()) return true;
|
||||||
|
return memcmp(mOldData.data(), mNewData.data(), mNewData.size()) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IEditPropertyCommand::SetEditComplete(bool IsComplete)
|
||||||
|
{
|
||||||
|
mCommandEnded = IsComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** IUndoCommand/QUndoCommand interface */
|
||||||
|
int IEditPropertyCommand::id() const
|
||||||
|
{
|
||||||
|
return eEditPropertyCmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEditPropertyCommand::mergeWith(const QUndoCommand *pkOther)
|
||||||
|
{
|
||||||
|
if (!mCommandEnded)
|
||||||
|
{
|
||||||
|
const IEditPropertyCommand* pkCmd = dynamic_cast<const IEditPropertyCommand*>(pkOther);
|
||||||
|
|
||||||
|
if (pkCmd && pkCmd->mIndex == mIndex && pkCmd->mpProperty == mpProperty)
|
||||||
|
{
|
||||||
|
std::vector<void*> MyPointers;
|
||||||
|
GetObjectDataPointers(MyPointers);
|
||||||
|
|
||||||
|
std::vector<void*> TheirPointers;
|
||||||
|
pkCmd->GetObjectDataPointers(TheirPointers);
|
||||||
|
|
||||||
|
if (TheirPointers.size() == MyPointers.size())
|
||||||
|
{
|
||||||
|
for (int PtrIdx = 0; PtrIdx < MyPointers.size(); PtrIdx++)
|
||||||
|
{
|
||||||
|
if (MyPointers[PtrIdx] != TheirPointers[PtrIdx])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match
|
||||||
|
mNewData = pkCmd->mNewData;
|
||||||
|
mCommandEnded = pkCmd->mCommandEnded;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IEditPropertyCommand::undo()
|
||||||
|
{
|
||||||
|
ASSERT(mSavedOldData && mSavedNewData);
|
||||||
|
RestoreObjectStateFromArray(mOldData);
|
||||||
|
mCommandEnded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IEditPropertyCommand::redo()
|
||||||
|
{
|
||||||
|
ASSERT(mSavedOldData && mSavedNewData);
|
||||||
|
RestoreObjectStateFromArray(mNewData);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEditPropertyCommand::AffectsCleanState() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef IEDITPROPERTYCOMMAND_H
|
||||||
|
#define IEDITPROPERTYCOMMAND_H
|
||||||
|
|
||||||
|
#include "IUndoCommand.h"
|
||||||
|
#include "EUndoCommand.h"
|
||||||
|
#include "Editor/PropertyEdit/CPropertyModel.h"
|
||||||
|
|
||||||
|
class IEditPropertyCommand : public IUndoCommand
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::vector<char> mOldData;
|
||||||
|
std::vector<char> mNewData;
|
||||||
|
|
||||||
|
QModelIndex mIndex;
|
||||||
|
CPropertyModel* mpModel;
|
||||||
|
IPropertyNew* mpProperty;
|
||||||
|
bool mCommandEnded;
|
||||||
|
bool mSavedOldData;
|
||||||
|
bool mSavedNewData;
|
||||||
|
|
||||||
|
/** Save the current state of the object properties to the given data buffer */
|
||||||
|
void SaveObjectStateToArray(std::vector<char>& rVector);
|
||||||
|
|
||||||
|
/** Restore the state of the object properties from the given data buffer */
|
||||||
|
void RestoreObjectStateFromArray(std::vector<char>& rArray);
|
||||||
|
|
||||||
|
public:
|
||||||
|
IEditPropertyCommand(
|
||||||
|
const QModelIndex& rkInIndex,
|
||||||
|
CPropertyModel* pInModel,
|
||||||
|
const QString& rkCommandName = "Edit Property"
|
||||||
|
);
|
||||||
|
|
||||||
|
void SaveOldData();
|
||||||
|
void SaveNewData();
|
||||||
|
bool IsNewDataDifferent();
|
||||||
|
void SetEditComplete(bool IsComplete);
|
||||||
|
|
||||||
|
/** Interface */
|
||||||
|
virtual void GetObjectDataPointers(std::vector<void*>& rOutPointers) const = 0;
|
||||||
|
|
||||||
|
/** IUndoCommand/QUndoCommand interface */
|
||||||
|
int id() const;
|
||||||
|
bool mergeWith(const QUndoCommand *pkOther);
|
||||||
|
void undo();
|
||||||
|
void redo();
|
||||||
|
bool AffectsCleanState() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IEDITPROPERTYCOMMAND_H
|
Loading…
Reference in New Issue