Reimplemented array resizing
This commit is contained in:
parent
641cf81dd8
commit
a90f1d0441
|
@ -199,7 +199,8 @@ HEADERS += \
|
|||
CGeneratePropertyNamesDialog.h \
|
||||
CProgressBarNotifier.h \
|
||||
Widgets/CCheckableTreeWidgetItem.h \
|
||||
Widgets/CCheckableTreeWidget.h
|
||||
Widgets/CCheckableTreeWidget.h \
|
||||
Undo/IEditPropertyCommand.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
|
@ -237,8 +238,6 @@ SOURCES += \
|
|||
PropertyEdit/CPropertyDelegate.cpp \
|
||||
PropertyEdit/CPropertyView.cpp \
|
||||
WorldEditor/CInstancesModel.cpp \
|
||||
Undo/CEditScriptPropertyCommand.cpp \
|
||||
Undo/CResizeScriptArrayCommand.cpp \
|
||||
WorldEditor/WEditorProperties.cpp \
|
||||
Undo/CChangeLayerCommand.cpp \
|
||||
WorldEditor/CTemplateEditDialog.cpp \
|
||||
|
@ -275,7 +274,8 @@ SOURCES += \
|
|||
ResourceBrowser/CVirtualDirectoryModel.cpp \
|
||||
ResourceBrowser/CVirtualDirectoryTreeView.cpp \
|
||||
CPropertyNameValidator.cpp \
|
||||
CGeneratePropertyNamesDialog.cpp
|
||||
CGeneratePropertyNamesDialog.cpp \
|
||||
Undo/IEditPropertyCommand.cpp
|
||||
|
||||
# UI Files
|
||||
FORMS += \
|
||||
|
|
|
@ -365,7 +365,7 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
|||
if (Type != EPropertyTypeNew::Array)
|
||||
{
|
||||
// TODO: support this for non script object properties
|
||||
pCommand = new CEditScriptPropertyCommand(mpEditor, mpModel->GetScriptObject(), pProp);
|
||||
pCommand = new CEditScriptPropertyCommand(mpEditor, rkIndex, mpModel);
|
||||
pCommand->SaveOldData();
|
||||
|
||||
// Handle sub-properties of flags and animation sets
|
||||
|
@ -478,18 +478,22 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
|||
// Array
|
||||
else
|
||||
{
|
||||
//FIXME
|
||||
/*
|
||||
pCommand = new CResizeScriptArrayCommand(mpEditor, rkIndex, mpModel);
|
||||
pCommand->SaveOldData();
|
||||
|
||||
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
||||
CArrayProperty* pArray = static_cast<CArrayProperty*>(pProp);
|
||||
int OldCount = pArray->ArrayCount(pData);
|
||||
int NewCount = pSpinBox->value();
|
||||
|
||||
if (pArray->Count() != NewCount)
|
||||
if (OldCount != NewCount)
|
||||
{
|
||||
CResizeScriptArrayCommand *pCmd = new CResizeScriptArrayCommand(pProp, mpEditor, mpModel, NewCount);
|
||||
mpEditor->UndoStack()->push(pCmd);
|
||||
mpModel->ArrayAboutToBeResized(rkIndex, NewCount);
|
||||
pArray->Resize(pData, NewCount);
|
||||
mpModel->ArrayResized(rkIndex, OldCount);
|
||||
}
|
||||
*/
|
||||
|
||||
pCommand->SaveNewData();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,13 +13,25 @@ CPropertyModel::CPropertyModel(QObject *pParent /*= 0*/)
|
|||
, mpPropertyData(nullptr)
|
||||
, mBoldModifiedProperties(true)
|
||||
, mShowNameValidity(false)
|
||||
, mFirstUnusedID(-1)
|
||||
{
|
||||
}
|
||||
|
||||
int CPropertyModel::RecursiveBuildArrays(IPropertyNew* pProperty, int ParentID)
|
||||
{
|
||||
int MyID = mProperties.size();
|
||||
mProperties << SProperty();
|
||||
// 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[MyID].pProperty = pProperty;
|
||||
mProperties[MyID].ParentID = ParentID;
|
||||
|
@ -70,6 +82,7 @@ void CPropertyModel::ConfigureIntrinsic(CGameProject* pProject, IPropertyNew* pR
|
|||
|
||||
mProperties.clear();
|
||||
mPropertyToIDMap.clear();
|
||||
mFirstUnusedID = -1;
|
||||
|
||||
if (pRootProperty)
|
||||
RecursiveBuildArrays(pRootProperty, -1);
|
||||
|
@ -532,37 +545,80 @@ void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex)
|
|||
|
||||
void CPropertyModel::ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize)
|
||||
{
|
||||
//FIXME
|
||||
/*QModelIndex Index = rkIndex.sibling(rkIndex.row(), 0);
|
||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(Index, false));
|
||||
QModelIndex Index = rkIndex.sibling(rkIndex.row(), 0);
|
||||
IPropertyNew* pProperty = PropertyForIndex(Index, false);
|
||||
CArrayProperty* pArray = TPropCast<CArrayProperty>(pProperty);
|
||||
ASSERT(pArray);
|
||||
|
||||
if (pArray && pArray->Type() == eArrayProperty)
|
||||
void* pArrayData = DataPointerForIndex(Index);
|
||||
u32 OldSize = pArray->ArrayCount(pArrayData);
|
||||
|
||||
if (NewSize != OldSize)
|
||||
{
|
||||
u32 OldSize = pArray->Count();
|
||||
|
||||
if (NewSize != OldSize)
|
||||
{
|
||||
if (NewSize > OldSize)
|
||||
beginInsertRows(Index, OldSize, NewSize - 1);
|
||||
else
|
||||
beginRemoveRows(Index, NewSize, OldSize - 1);
|
||||
}
|
||||
}*/
|
||||
if (NewSize > OldSize)
|
||||
beginInsertRows(Index, OldSize, NewSize - 1);
|
||||
else
|
||||
beginRemoveRows(Index, NewSize, OldSize - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void CPropertyModel::ArrayResized(const QModelIndex& rkIndex, u32 OldSize)
|
||||
{
|
||||
//FIXME
|
||||
/*CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(rkIndex, false));
|
||||
u32 NewSize = pArray->Count();
|
||||
QModelIndex Index = rkIndex.sibling(rkIndex.row(), 0);
|
||||
IPropertyNew* pProperty = PropertyForIndex(Index, false);
|
||||
CArrayProperty* pArray = TPropCast<CArrayProperty>(pProperty);
|
||||
ASSERT(pArray);
|
||||
|
||||
void* pArrayData = DataPointerForIndex(Index);
|
||||
u32 NewSize = pArray->ArrayCount(pArrayData);
|
||||
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
|
|
|
@ -18,6 +18,7 @@ class CPropertyModel : public QAbstractItemModel
|
|||
};
|
||||
QVector<SProperty> mProperties;
|
||||
QMap<IPropertyNew*, int> mPropertyToIDMap;
|
||||
int mFirstUnusedID;
|
||||
|
||||
CGameProject* mpProject;
|
||||
CScriptObject* mpObject; // may be null
|
||||
|
@ -49,6 +50,7 @@ public:
|
|||
void ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize);
|
||||
void ArrayResized(const QModelIndex& rkIndex, u32 OldSize);
|
||||
void ResizeArray(const QModelIndex& rkIndex, u32 NewSize);
|
||||
void ClearSlot(int ID);
|
||||
|
||||
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
|
||||
#define CEDITSCRIPTPROPERTYCOMMAND_H
|
||||
|
||||
#include "IUndoCommand.h"
|
||||
#include "IEditPropertyCommand.h"
|
||||
#include "ObjReferences.h"
|
||||
#include "EUndoCommand.h"
|
||||
#include "Editor/PropertyEdit/CPropertyModel.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
|
||||
{
|
||||
std::vector<CInstancePtr> mInstances;
|
||||
CWorldEditor* mpEditor;
|
||||
|
||||
public:
|
||||
CEditScriptPropertyCommand(CWorldEditor* pEditor, CScriptObject* pInstance, IPropertyNew* pProperty, const QString& rkCommandName = "Edit Property")
|
||||
: IEditPropertyCommand(pProperty, rkCommandName)
|
||||
CEditScriptPropertyCommand(CWorldEditor* pEditor, const QModelIndex& rkIndex, CPropertyModel* pInModel, const QString& rkCommandName = "Edit Property")
|
||||
: IEditPropertyCommand(rkIndex, pInModel, rkCommandName)
|
||||
, mpEditor(pEditor)
|
||||
{
|
||||
mInstances.push_back( CInstancePtr(pInstance) );
|
||||
mInstances.push_back( CInstancePtr(pInModel->GetScriptObject()) );
|
||||
}
|
||||
|
||||
virtual void GetObjectDataPointers(std::vector<void*>& rOutPointers) const override
|
||||
{
|
||||
rOutPointers.resize(mInstances.size());
|
||||
|
||||
for (int InstanceIdx = 0; InstanceIdx < mInstances.size(); InstanceIdx++)
|
||||
{
|
||||
rOutPointers[InstanceIdx] = mInstances[InstanceIdx]->PropertyData();
|
||||
}
|
||||
//@todo support multiple objects
|
||||
rOutPointers[0] = mpModel->DataPointerForIndex(mIndex);
|
||||
}
|
||||
|
||||
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
|
||||
#define CRESIZESCRIPTARRAYCOMMAND_H
|
||||
|
||||
#include "IUndoCommand.h"
|
||||
#include "ObjReferences.h"
|
||||
#include "Editor/PropertyEdit/CPropertyModel.h"
|
||||
#include "Editor/WorldEditor/CWorldEditor.h"
|
||||
#include <QUndoCommand>
|
||||
#include "CEditScriptPropertyCommand.h"
|
||||
|
||||
// todo: make this more general... it shouldn't be relying on a CPropertyModel pointer
|
||||
//FIXME
|
||||
/*class CResizeScriptArrayCommand : public IUndoCommand
|
||||
class CResizeScriptArrayCommand : public CEditScriptPropertyCommand
|
||||
{
|
||||
CWorldEditor* mpEditor;
|
||||
IPropertyNew* mpArray;
|
||||
QVector<IPropertyNew*> mDeletedProperties;
|
||||
CPropertyModel *mpModel;
|
||||
|
||||
int mOldSize;
|
||||
int mNewSize;
|
||||
bool mNewSizeLarger;
|
||||
|
||||
public:
|
||||
CResizeScriptArrayCommand(IPropertyNew *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize);
|
||||
~CResizeScriptArrayCommand();
|
||||
void undo();
|
||||
void redo();
|
||||
bool AffectsCleanState() const { return true; }
|
||||
};*/
|
||||
CResizeScriptArrayCommand(CWorldEditor* pEditor, const QModelIndex& rkIndex, CPropertyModel* pInModel, const QString& rkCommandName = "Resize Array")
|
||||
: CEditScriptPropertyCommand(pEditor, rkIndex, pInModel, rkCommandName)
|
||||
{}
|
||||
|
||||
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
|
||||
|
|
|
@ -8,7 +8,7 @@ enum EUndoCommand
|
|||
eTranslateNodeCmd,
|
||||
eRotateNodeCmd,
|
||||
eScaleNodeCmd,
|
||||
eEditScriptPropertyCmd
|
||||
eEditPropertyCmd
|
||||
};
|
||||
|
||||
#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