Support for undo/redo on array resize
This commit is contained in:
parent
cc054cf571
commit
f6f36f4f2e
|
@ -23,6 +23,19 @@ TIDString IProperty::IDString(bool FullPath) const
|
|||
}
|
||||
|
||||
// ************ CPropertyStruct ************
|
||||
void CPropertyStruct::Copy(const IProperty *pkProp)
|
||||
{
|
||||
const CPropertyStruct *pkSource = static_cast<const CPropertyStruct*>(pkProp);
|
||||
|
||||
for (auto it = mProperties.begin(); it != mProperties.end(); it++)
|
||||
delete *it;
|
||||
|
||||
mProperties.resize(pkSource->mProperties.size());
|
||||
|
||||
for (u32 iSub = 0; iSub < mProperties.size(); iSub++)
|
||||
mProperties[iSub] = pkSource->mProperties[iSub]->Clone(this);
|
||||
}
|
||||
|
||||
IProperty* CPropertyStruct::PropertyByIndex(u32 index) const
|
||||
{
|
||||
return mProperties[index];
|
||||
|
|
|
@ -41,8 +41,11 @@ public:
|
|||
virtual EPropertyType Type() const = 0;
|
||||
virtual TString ToString() const { return ""; }
|
||||
virtual IPropertyValue* RawValue() { return nullptr; }
|
||||
virtual void Copy(const IProperty *pkProp) = 0;
|
||||
virtual IProperty* Clone(CPropertyStruct *pParent = 0) const = 0;
|
||||
|
||||
inline CPropertyStruct* Parent() const { return mpParent; }
|
||||
inline void SetParent(CPropertyStruct *pParent) { mpParent = pParent; }
|
||||
|
||||
// These functions can't be in the header to avoid circular includes with IPropertyTemplate.h
|
||||
IPropertyTemplate* Template() const;
|
||||
|
@ -71,6 +74,21 @@ public:
|
|||
virtual TString ToString() const { return mValue.ToString(); }
|
||||
virtual IPropertyValue* RawValue() { return &mValue; }
|
||||
|
||||
virtual void Copy(const IProperty *pkProp)
|
||||
{
|
||||
const TTypedProperty *pkCast = static_cast<const TTypedProperty*>(pkProp);
|
||||
mValue.Set(pkCast->mValue.Get());
|
||||
}
|
||||
|
||||
virtual TTypedProperty* Clone(CPropertyStruct *pParent) const
|
||||
{
|
||||
if (!pParent) pParent = mpParent;
|
||||
|
||||
TTypedProperty *pOut = new TTypedProperty(mpTemplate, pParent);
|
||||
pOut->Copy(this);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
inline PropType Get() const { return mValue.Get(); }
|
||||
inline void Set(PropType v) { mValue.Set(v); }
|
||||
};
|
||||
|
@ -107,6 +125,16 @@ public:
|
|||
|
||||
EPropertyType Type() const { return eStructProperty; }
|
||||
|
||||
virtual void Copy(const IProperty *pkProp);
|
||||
|
||||
virtual IProperty* Clone(CPropertyStruct *pParent) const
|
||||
{
|
||||
if (!pParent) pParent = mpParent;
|
||||
CPropertyStruct *pOut = new CPropertyStruct(mpTemplate, pParent);
|
||||
pOut->Copy(this);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
// Inline
|
||||
inline u32 Count() const { return mProperties.size(); }
|
||||
inline void AddSubProperty(IProperty *pProp) { mProperties.push_back(pProp); }
|
||||
|
@ -134,6 +162,14 @@ public:
|
|||
|
||||
EPropertyType Type() const { return eArrayProperty; }
|
||||
|
||||
virtual IProperty* Clone(CPropertyStruct *pParent) const
|
||||
{
|
||||
if (!pParent) pParent = mpParent;
|
||||
CArrayProperty *pOut = new CArrayProperty(mpTemplate, pParent);
|
||||
pOut->Copy(this);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
// Inline
|
||||
inline void Reserve(u32 amount) { mProperties.reserve(amount); }
|
||||
|
||||
|
|
|
@ -134,7 +134,9 @@ HEADERS += \
|
|||
PropertyEdit/CPropertyRelay.h \
|
||||
WorldEditor/CInstancesProxyModel.h \
|
||||
WorldEditor/CInstancesModel.h \
|
||||
Undo/CEditScriptPropertyCommand.h
|
||||
Undo/CEditScriptPropertyCommand.h \
|
||||
Undo/CResizeScriptArrayCommand.h \
|
||||
Undo/CBasicPropertyCommand.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
|
@ -186,7 +188,9 @@ SOURCES += \
|
|||
PropertyEdit/CPropertyDelegate.cpp \
|
||||
PropertyEdit/CPropertyView.cpp \
|
||||
WorldEditor/CInstancesModel.cpp \
|
||||
Undo/CEditScriptPropertyCommand.cpp
|
||||
Undo/CEditScriptPropertyCommand.cpp \
|
||||
Undo/CResizeScriptArrayCommand.cpp \
|
||||
Undo/CBasicPropertyCommand.cpp
|
||||
|
||||
# UI Files
|
||||
FORMS += \
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Editor/UICommon.h"
|
||||
#include "Editor/Undo/CEditScriptPropertyCommand.h"
|
||||
#include "Editor/Undo/CResizeScriptArrayCommand.h"
|
||||
#include "Editor/Widgets/WColorPicker.h"
|
||||
#include "Editor/Widgets/WDraggableSpinBox.h"
|
||||
#include "Editor/Widgets/WIntegralSpinBox.h"
|
||||
|
@ -351,7 +352,8 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
|||
|
||||
if (pProp)
|
||||
{
|
||||
pOldValue = pProp->RawValue()->Clone();
|
||||
IPropertyValue *pRawValue = pProp->RawValue();
|
||||
pOldValue = pRawValue ? pRawValue->Clone() : nullptr;
|
||||
|
||||
switch (pProp->Type())
|
||||
{
|
||||
|
@ -430,8 +432,14 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
|||
case eArrayProperty:
|
||||
{
|
||||
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
|
||||
u32 NewCount = pSpinBox->value();
|
||||
mpModel->ResizeArray(rkIndex, NewCount);
|
||||
|
||||
if (pArray->Count() != NewCount)
|
||||
{
|
||||
CResizeScriptArrayCommand *pCmd = new CResizeScriptArrayCommand(mpModel, rkIndex, NewCount);
|
||||
mpEditor->UndoStack()->push(pCmd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -442,7 +450,9 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
|||
else if (rkIndex.internalId() & 0x1)
|
||||
{
|
||||
pProp = mpModel->PropertyForIndex(rkIndex, true);
|
||||
pOldValue = pProp->RawValue()->Clone();
|
||||
|
||||
IPropertyValue *pOldValue = pProp->RawValue();
|
||||
pOldValue = pOldValue ? pOldValue->Clone() : nullptr;
|
||||
|
||||
if (pProp->Type() == eCharacterProperty)
|
||||
SetCharacterModelData(pEditor, rkIndex);
|
||||
|
@ -490,7 +500,7 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
|||
}
|
||||
}
|
||||
|
||||
if (pProp)
|
||||
if (pProp && pOldValue)
|
||||
{
|
||||
// Check for edit in progress
|
||||
bool Matches = pOldValue->Matches(pProp->RawValue());
|
||||
|
|
|
@ -409,29 +409,35 @@ void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex)
|
|||
emit PropertyModified(rkIndex);
|
||||
}
|
||||
|
||||
void CPropertyModel::ResizeArray(const QModelIndex& rkIndex, u32 NewSize)
|
||||
void CPropertyModel::ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize)
|
||||
{
|
||||
QModelIndex Index = index(rkIndex.row(), 0, rkIndex.parent());
|
||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(rkIndex, false));
|
||||
QModelIndex Index = rkIndex.sibling(rkIndex.row(), 0);
|
||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(Index, false));
|
||||
|
||||
if (pArray && pArray->Type() == eArrayProperty)
|
||||
{
|
||||
u32 OldSize = pArray->Count();
|
||||
|
||||
if (OldSize != NewSize)
|
||||
{
|
||||
if (OldSize < NewSize)
|
||||
if (NewSize != OldSize)
|
||||
{
|
||||
if (NewSize > OldSize)
|
||||
beginInsertRows(Index, OldSize, NewSize - 1);
|
||||
pArray->Resize(NewSize);
|
||||
endInsertRows();
|
||||
}
|
||||
else
|
||||
{
|
||||
beginRemoveRows(Index, NewSize, OldSize - 1);
|
||||
pArray->Resize(NewSize);
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPropertyModel::ArrayResized(const QModelIndex& rkIndex, u32 OldSize)
|
||||
{
|
||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(rkIndex, false));
|
||||
u32 NewSize = pArray->Count();
|
||||
|
||||
if (NewSize != OldSize)
|
||||
{
|
||||
if (pArray->Count() > OldSize)
|
||||
endInsertRows();
|
||||
else
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,8 +24,9 @@ public:
|
|||
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);
|
||||
|
||||
signals:
|
||||
void PropertyModified(const QModelIndex& rkIndex);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
#include "CBasicPropertyCommand.h"
|
||||
#include <Core/Resource/Script/IPropertyTemplate.h>
|
||||
|
||||
CBasicPropertyCommand::CBasicPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex)
|
||||
: QUndoCommand("Edit Property")
|
||||
, mpModel(pModel)
|
||||
, mpProperty(pModel->PropertyForIndex(rkIndex, true))
|
||||
, mpTemplate(mpProperty->Template())
|
||||
, mIndex(rkIndex)
|
||||
, mIsInArray(false)
|
||||
{
|
||||
// Check for array
|
||||
IProperty *pProp = mpProperty;
|
||||
IProperty *pParent = mpProperty->Parent();
|
||||
|
||||
while (pParent)
|
||||
{
|
||||
if (pParent->Type() == eArrayProperty)
|
||||
{
|
||||
mIsInArray = true;
|
||||
|
||||
// Find array index
|
||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(pParent);
|
||||
|
||||
for (u32 iSub = 0; iSub < pArray->Count(); iSub++)
|
||||
{
|
||||
if (pArray->PropertyByIndex(iSub) == pProp)
|
||||
{
|
||||
mArrayIndices << iSub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pProp = 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.
|
||||
IPropertyTemplate *pTemp = mpTemplate;
|
||||
CStructTemplate *pParent = mpTemplate->Parent();
|
||||
|
||||
QVector<u32> SubIndices;
|
||||
int IndexIndex = 0;
|
||||
|
||||
if (mIndex.internalId() & 0x1)
|
||||
SubIndices << mIndex.row();
|
||||
|
||||
while (pParent)
|
||||
{
|
||||
if (pParent->Type() != eArrayProperty || static_cast<CArrayTemplate*>(pParent)->Count() > 1)
|
||||
{
|
||||
for (u32 iSub = 0; iSub < pParent->Count(); iSub++)
|
||||
{
|
||||
if (pParent->PropertyByIndex(iSub) == pTemp)
|
||||
{
|
||||
SubIndices << iSub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pParent->Type() == eArrayProperty)
|
||||
{
|
||||
SubIndices << mArrayIndices[IndexIndex];
|
||||
IndexIndex++;
|
||||
}
|
||||
|
||||
pTemp = pParent;
|
||||
pParent = pParent->Parent();
|
||||
}
|
||||
|
||||
// Find corresponding index
|
||||
QModelIndex Index = QModelIndex();
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef CBASICPROPERTYCOMMAND_H
|
||||
#define CBASICPROPERTYCOMMAND_H
|
||||
|
||||
#include "Editor/PropertyEdit/CPropertyModel.h"
|
||||
#include <QUndoCommand>
|
||||
|
||||
class CBasicPropertyCommand : public QUndoCommand
|
||||
{
|
||||
protected:
|
||||
CPropertyModel *mpModel;
|
||||
IProperty *mpProperty;
|
||||
IPropertyTemplate *mpTemplate;
|
||||
QModelIndex mIndex;
|
||||
|
||||
bool mIsInArray;
|
||||
QVector<u32> mArrayIndices;
|
||||
|
||||
public:
|
||||
CBasicPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex);
|
||||
virtual void UpdateArraySubProperty();
|
||||
};
|
||||
|
||||
#endif // CBASICPROPERTYCOMMAND_H
|
|
@ -2,12 +2,9 @@
|
|||
#include "EUndoCommand.h"
|
||||
|
||||
CEditScriptPropertyCommand::CEditScriptPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, IPropertyValue *pOldValue, bool IsDone)
|
||||
: QUndoCommand("Edit Property")
|
||||
, mpModel(pModel)
|
||||
, mIndex(rkIndex)
|
||||
: CBasicPropertyCommand(pModel, rkIndex)
|
||||
, mCommandEnded(IsDone)
|
||||
{
|
||||
mpProperty = pModel->PropertyForIndex(rkIndex, true);
|
||||
mpOldValue = pOldValue;
|
||||
mpNewValue = mpProperty->RawValue()->Clone();
|
||||
}
|
||||
|
@ -42,12 +39,14 @@ bool CEditScriptPropertyCommand::mergeWith(const QUndoCommand *pkOther)
|
|||
|
||||
void CEditScriptPropertyCommand::undo()
|
||||
{
|
||||
if (mIsInArray) UpdateArraySubProperty();
|
||||
mpProperty->RawValue()->Copy(mpOldValue);
|
||||
mpModel->NotifyPropertyModified(mIndex);
|
||||
}
|
||||
|
||||
void CEditScriptPropertyCommand::redo()
|
||||
{
|
||||
if (mIsInArray) UpdateArraySubProperty();
|
||||
mpProperty->RawValue()->Copy(mpNewValue);
|
||||
mpModel->NotifyPropertyModified(mIndex);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
#ifndef CEDITSCRIPTPROPERTYCOMMAND_H
|
||||
#define CEDITSCRIPTPROPERTYCOMMAND_H
|
||||
|
||||
#include "Editor/PropertyEdit/CPropertyDelegate.h"
|
||||
#include "CBasicPropertyCommand.h"
|
||||
#include "Editor/PropertyEdit/CPropertyModel.h"
|
||||
#include <QUndoCommand>
|
||||
|
||||
class CEditScriptPropertyCommand : public QUndoCommand
|
||||
class CEditScriptPropertyCommand : public CBasicPropertyCommand
|
||||
{
|
||||
CPropertyModel *mpModel;
|
||||
IProperty *mpProperty;
|
||||
QModelIndex mIndex;
|
||||
|
||||
IPropertyValue *mpOldValue;
|
||||
IPropertyValue *mpNewValue;
|
||||
bool mCommandEnded;
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#include "CResizeScriptArrayCommand.h"
|
||||
|
||||
CResizeScriptArrayCommand::CResizeScriptArrayCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, u32 NewSize)
|
||||
: CBasicPropertyCommand(pModel, rkIndex)
|
||||
, mpArray(static_cast<CArrayProperty*>(mpProperty))
|
||||
, mOldSize(mpArray->Count())
|
||||
, mNewSize(NewSize)
|
||||
{
|
||||
mNewSizeLarger = mNewSize > mOldSize;
|
||||
|
||||
if (!mNewSizeLarger)
|
||||
{
|
||||
for (u32 iSub = mNewSize; iSub < mOldSize; iSub++)
|
||||
{
|
||||
mDeletedProperties << mpArray->PropertyByIndex(iSub)->Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CResizeScriptArrayCommand::~CResizeScriptArrayCommand()
|
||||
{
|
||||
foreach (IProperty *pProp, mDeletedProperties)
|
||||
delete pProp;
|
||||
}
|
||||
|
||||
void CResizeScriptArrayCommand::undo()
|
||||
{
|
||||
if (mNewSize != mOldSize)
|
||||
{
|
||||
if (mIsInArray) UpdateArraySubProperty();
|
||||
|
||||
mpModel->ArrayAboutToBeResized(mIndex, mOldSize);
|
||||
mpArray->Resize(mOldSize);
|
||||
|
||||
if (!mNewSizeLarger)
|
||||
{
|
||||
u32 NumNewElements = mOldSize - mNewSize;
|
||||
|
||||
for (u32 iSub = 0; iSub < NumNewElements; iSub++)
|
||||
{
|
||||
u32 Idx = iSub + mNewSize;
|
||||
mpArray->PropertyByIndex(Idx)->Copy(mDeletedProperties[iSub]);
|
||||
}
|
||||
}
|
||||
|
||||
mpModel->ArrayResized(mIndex, 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)
|
||||
{
|
||||
if (mIsInArray) UpdateArraySubProperty();
|
||||
|
||||
mpModel->ArrayAboutToBeResized(mIndex, mNewSize);
|
||||
mpArray->Resize(mNewSize);
|
||||
mpModel->ArrayResized(mIndex, mOldSize);
|
||||
}
|
||||
}
|
||||
|
||||
void CResizeScriptArrayCommand::UpdateArraySubProperty()
|
||||
{
|
||||
CArrayProperty *pOldArray = mpArray;
|
||||
CBasicPropertyCommand::UpdateArraySubProperty();
|
||||
mpArray = static_cast<CArrayProperty*>(mpProperty);
|
||||
|
||||
if (pOldArray != mpArray)
|
||||
{
|
||||
for (int iDel = 0; iDel < mDeletedProperties.size(); iDel++)
|
||||
mDeletedProperties[iDel]->SetParent(mpArray);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef CRESIZESCRIPTARRAYCOMMAND_H
|
||||
#define CRESIZESCRIPTARRAYCOMMAND_H
|
||||
|
||||
#include "CBasicPropertyCommand.h"
|
||||
#include "Editor/PropertyEdit/CPropertyModel.h"
|
||||
#include <QUndoCommand>
|
||||
|
||||
class CResizeScriptArrayCommand : public CBasicPropertyCommand
|
||||
{
|
||||
CArrayProperty *mpArray;
|
||||
QVector<IProperty*> mDeletedProperties;
|
||||
|
||||
u32 mOldSize;
|
||||
u32 mNewSize;
|
||||
bool mNewSizeLarger;
|
||||
|
||||
public:
|
||||
CResizeScriptArrayCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, u32 NewSize);
|
||||
~CResizeScriptArrayCommand();
|
||||
void undo();
|
||||
void redo();
|
||||
virtual void UpdateArraySubProperty();
|
||||
};
|
||||
|
||||
#endif // CRESIZESCRIPTARRAYCOMMAND_H
|
|
@ -10,6 +10,7 @@
|
|||
#include "CSelectAllCommand.h"
|
||||
#include "CInvertSelectionCommand.h"
|
||||
#include "CEditScriptPropertyCommand.h"
|
||||
#include "CResizeScriptArrayCommand.h"
|
||||
#include "EUndoCommand.h"
|
||||
|
||||
#endif // UNDOCOMMANDS
|
||||
|
|
Loading…
Reference in New Issue