Added interface for editing array properties in the property view

This commit is contained in:
parax0 2016-01-25 16:57:04 -07:00
parent 3b41415581
commit 9a24a34bc6
12 changed files with 185 additions and 48 deletions

View File

@ -130,9 +130,9 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY)
for (u32 iElem = 0; iElem < Size; iElem++)
{
if (mVersion < eEchoesDemo)
LoadStructMP1(SCLY, pArrayCast->ElementByIndex(iElem), pArrayCast->SubStructTemplate());
LoadStructMP1(SCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate());
else
LoadStructMP2(SCLY, pArrayCast->ElementByIndex(iElem), pArrayCast->SubStructTemplate());
LoadStructMP2(SCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate());
}
break;
}

View File

@ -23,12 +23,6 @@ TIDString IProperty::IDString(bool FullPath) const
}
// ************ CPropertyStruct ************
CPropertyStruct::~CPropertyStruct()
{
for (auto it = mProperties.begin(); it != mProperties.end(); it++)
delete *it;
}
IProperty* CPropertyStruct::PropertyByIndex(u32 index) const
{
return mProperties[index];
@ -106,21 +100,21 @@ CPropertyStruct* CPropertyStruct::StructByIDString(const TIDString& rkStr) const
// ************ CArrayProperty ************
void CArrayProperty::Resize(u32 Size)
{
u32 OldSize = mSubStructs.size();
u32 OldSize = mProperties.size();
if (OldSize == Size) return;
if (Size < OldSize)
{
for (u32 i = mSubStructs.size() - 1; i >= Size; i--)
delete mSubStructs[i];
for (u32 i = mProperties.size() - 1; i >= Size; i--)
delete mProperties[i];
}
mSubStructs.resize(Size);
mProperties.resize(Size);
if (Size > OldSize)
{
for (u32 i = OldSize; i < Size; i++)
mSubStructs[i] = static_cast<CArrayTemplate*>(mpTemplate)->CreateSubStruct();
mProperties[i] = static_cast<CArrayTemplate*>(mpTemplate)->CreateSubStruct(this);
}
}
@ -129,3 +123,8 @@ CStructTemplate* CArrayProperty::SubStructTemplate() const
// CArrayTemplate inherits from CStructTemplate. The template defines the substruct structure.
return static_cast<CStructTemplate*>(Template());
}
TString CArrayProperty::ElementName() const
{
return static_cast<CArrayTemplate*>(Template())->ElementName();
}

View File

@ -92,12 +92,16 @@ typedef TTypedProperty<std::vector<u8>, eUnknownProperty, CUnknownValue>
class CPropertyStruct : public IProperty
{
friend class CScriptLoader;
protected:
std::vector<IProperty*> mProperties;
public:
CPropertyStruct(IPropertyTemplate *pTemp, CPropertyStruct *pParent)
: IProperty(pTemp, pParent) {}
~CPropertyStruct();
~CPropertyStruct() {
for (auto it = mProperties.begin(); it != mProperties.end(); it++)
delete *it;
}
EPropertyType Type() const { return eStructProperty; }
@ -118,31 +122,23 @@ public:
/*
* CArrayProperty stores a repeated property struct.
*/
class CArrayProperty : public IProperty
class CArrayProperty : public CPropertyStruct
{
friend class CScriptLoader;
std::vector<CPropertyStruct*> mSubStructs;
public:
CArrayProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent)
: IProperty(pTemp, pParent) {}
~CArrayProperty() {
for (u32 iSub = 0; iSub < mSubStructs.size(); iSub++)
delete mSubStructs[iSub];
}
: CPropertyStruct(pTemp, pParent) {}
EPropertyType Type() const { return eArrayProperty; }
// Inline
inline u32 Count() const { return mSubStructs.size(); }
inline void Reserve(u32 amount) { mSubStructs.reserve(amount); }
inline CPropertyStruct* ElementByIndex(u32 index) { return mSubStructs[index]; }
inline CPropertyStruct* operator[](u32 index) { return ElementByIndex(index); }
inline void Reserve(u32 amount) { mProperties.reserve(amount); }
// Functions
void Resize(u32 Size);
CStructTemplate* SubStructTemplate() const;
TString ElementName() const;
};
#endif // IPROPERTY

View File

@ -502,6 +502,7 @@ class CArrayTemplate : public CStructTemplate
{
friend class CTemplateLoader;
friend class CTemplateWriter;
TString mElementName;
public:
CArrayTemplate(u32 ID, CStructTemplate *pParent = 0)
@ -518,14 +519,25 @@ public:
EPropertyType Type() const { return eArrayProperty; }
void SetParam(const TString& rkParamName, const TString& rkValue)
{
if (rkParamName == "element_name")
mElementName = rkValue;
else
CStructTemplate::SetParam(rkParamName, rkValue);
}
IProperty* InstantiateProperty(CPropertyStruct *pParent)
{
return new CArrayProperty(this, pParent);
}
CPropertyStruct* CreateSubStruct()
TString ElementName() const { return mElementName; }
void SetElementName(const TString& rkName) { mElementName = rkName; }
CPropertyStruct* CreateSubStruct(CArrayProperty *pArray)
{
return (CPropertyStruct*) CStructTemplate::InstantiateProperty(nullptr);
return (CPropertyStruct*) CStructTemplate::InstantiateProperty(pArray);
}
};

View File

@ -47,9 +47,22 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
break;
case eShortProperty:
case eLongProperty:
pOut = new WIntegralSpinBox(pParent);
{
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT16_MIN);
pSpinBox->setMaximum(INT16_MAX);
pOut = pSpinBox;
break;
}
case eLongProperty:
{
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT32_MIN);
pSpinBox->setMaximum(INT32_MAX);
pOut = pSpinBox;
break;
}
case eFloatProperty:
{
@ -93,6 +106,15 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
break;
}
case eArrayProperty:
{
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(0);
pSpinBox->setMaximum(999);
pOut = pSpinBox;
break;
}
}
}
@ -222,6 +244,14 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
break;
}
case eArrayProperty:
{
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
pSpinBox->setValue(pArray->Count());
break;
}
}
}
@ -352,6 +382,14 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
break;
}
case eArrayProperty:
{
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
u32 NewCount = pSpinBox->value();
mpModel->ResizeArray(rkIndex, NewCount);
break;
}
}
}

View File

@ -43,13 +43,16 @@ int CPropertyModel::columnCount(const QModelIndex& /*rkParent*/) const
int CPropertyModel::rowCount(const QModelIndex& rkParent) const
{
if (!mpBaseStruct) return 0;
if (!rkParent.isValid()) return mpBaseStruct->Count();
if (rkParent.column() != 0) return 0;
if (rkParent.internalId() & 0x1) return 0;
IProperty *pProp = PropertyForIndex(rkParent, false);
if (pProp == mpBaseStruct) return mpBaseStruct->Count();
switch (pProp->Type())
{
case eStructProperty:
case eArrayProperty:
return static_cast<CPropertyStruct*>(pProp)->Count();
case eBitfieldProperty:
@ -208,7 +211,30 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
IProperty *pProp = PropertyForIndex(rkIndex, false);
if (rkIndex.column() == 0)
{
// Check for arrays
IProperty *pParent = pProp->Parent();
if (pParent)
{
// For direct array sub-properties, display the element name instead of the property name (the property name is the array name)
if (pProp->Type() == eStructProperty && pParent->Type() == eArrayProperty)
{
TString ElementName = static_cast<CArrayProperty*>(pParent)->ElementName();
return QString("%1 %2").arg(TO_QSTRING(ElementName)).arg(rkIndex.row() + 1);
}
// Check whether the parent struct is an array element with one sub-property
if (pParent->Type() == eStructProperty && pParent->Parent() && pParent->Parent()->Type() == eArrayProperty)
{
if (static_cast<CPropertyStruct*>(pParent)->Count() == 1)
return QString("%1 %2").arg(TO_QSTRING(pProp->Name())).arg(rkIndex.row() + 1);
}
}
// Display property name for everything else
return TO_QSTRING(pProp->Name());
}
if (rkIndex.column() == 1)
{
@ -232,6 +258,13 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
}
else return "";
// Display the element count for arrays
case eArrayProperty:
{
u32 Count = static_cast<CArrayProperty*>(pProp)->Count();
return QString("%1 element%2").arg(Count).arg(Count != 1 ? "s" : "");
}
// No display text on properties with persistent editors
case eBoolProperty:
case eFileProperty:
@ -273,12 +306,8 @@ QModelIndex CPropertyModel::index(int Row, int Column, const QModelIndex& rkPare
if (!hasIndex(Row, Column, rkParent))
return QModelIndex();
// Root index
if (!rkParent.isValid())
return createIndex(Row, Column, mpBaseStruct->PropertyByIndex(Row));
// Check property for children
IProperty *pParent = PropertyForIndex(rkParent, false);
IProperty *pParent = (rkParent.isValid() ? PropertyForIndex(rkParent, false) : mpBaseStruct);
// Struct
if (pParent->Type() == eStructProperty)
@ -287,9 +316,22 @@ QModelIndex CPropertyModel::index(int Row, int Column, const QModelIndex& rkPare
return createIndex(Row, Column, pProp);
}
// Array
if (pParent->Type() == eArrayProperty)
{
IProperty *pProp = static_cast<CArrayProperty*>(pParent)->PropertyByIndex(Row);
// If this array element only has one sub-property then let's just skip the redundant tree node and show the sub-property directly.
CPropertyStruct *pStruct = static_cast<CPropertyStruct*>(pProp);
if (pStruct->Count() == 1)
pProp = pStruct->PropertyByIndex(0);
return createIndex(Row, Column, pProp);
}
// Other property
if (pParent->Type() == eColorProperty || pParent->Type() == eVector3Property || pParent->Type() == eBitfieldProperty || pParent->Type() == eCharacterProperty)
return createIndex(Row, Column, rkParent.internalId() | 0x1);
return createIndex(Row, Column, u32(pParent) | 0x1);
return QModelIndex();
}
@ -314,10 +356,22 @@ QModelIndex CPropertyModel::parent(const QModelIndex& rkChild) const
// Iterate over grandfather properties until we find the row
CPropertyStruct *pGrandparent = pParent->Parent();
// Check for array with one sub-property
if (pGrandparent->Type() == eArrayProperty)
{
CPropertyStruct *pStruct = static_cast<CPropertyStruct*>(pParent);
if (pStruct->Count() == 1)
{
pParent = pGrandparent;
pGrandparent = pGrandparent->Parent();
}
}
for (u32 iProp = 0; iProp < pGrandparent->Count(); iProp++)
{
if (pGrandparent->PropertyByIndex(iProp) == pParent)
return createIndex(iProp, rkChild.column(), pParent);
return createIndex(iProp, 0, pParent);
}
return QModelIndex();
@ -343,3 +397,30 @@ void CPropertyModel::UpdateSubProperties(const QModelIndex& rkIndex)
emit dataChanged( index(0, 1, rkIndex), index(3, 1, rkIndex), Roles);
}
}
void CPropertyModel::ResizeArray(const QModelIndex& rkIndex, u32 NewSize)
{
QModelIndex Index = index(rkIndex.row(), 0, rkIndex.parent());
CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(rkIndex, false));
if (pArray && pArray->Type() == eArrayProperty)
{
u32 OldSize = pArray->Count();
if (OldSize != NewSize)
{
if (OldSize < NewSize)
{
beginInsertRows(Index, OldSize, NewSize - 1);
pArray->Resize(NewSize);
endInsertRows();
}
else
{
beginRemoveRows(Index, NewSize, OldSize - 1);
pArray->Resize(NewSize);
endRemoveRows();
}
}
}
}

View File

@ -23,6 +23,7 @@ public:
QModelIndex parent(const QModelIndex& rkChild) const;
Qt::ItemFlags flags(const QModelIndex& rkIndex) const;
void UpdateSubProperties(const QModelIndex& rkIndex);
void ResizeArray(const QModelIndex& rkIndex, u32 NewSize);
};
#endif // CPROPERTYMODEL_H

View File

@ -1,6 +1,7 @@
#include "CPropertyView.h"
#include "CPropertyDelegate.h"
#include <Core/Resource/Script/IPropertyTemplate.h>
#include <QEvent>
#include <QToolTip>
@ -12,6 +13,9 @@ CPropertyView::CPropertyView(QWidget *pParent)
setItemDelegateForColumn(1, mpDelegate);
setEditTriggers(AllEditTriggers);
setModel(mpModel);
connect(mpModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(SetPersistentEditors(QModelIndex)));
connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(SetPersistentEditors(QModelIndex)));
}
void CPropertyView::setModel(QAbstractItemModel *pModel)
@ -104,7 +108,8 @@ void CPropertyView::SetPersistentEditors(const QModelIndex& rkParent)
break;
}
SetPersistentEditors(ChildIndex);
if (isExpanded(ChildIndex))
SetPersistentEditors(ChildIndex);
}
}

View File

@ -17,7 +17,9 @@ public:
void setModel(QAbstractItemModel *pModel);
bool event(QEvent *pEvent);
void SetBaseStruct(CPropertyStruct *pStruct);
void SetPersistentEditors(const QModelIndex& rkParent);
public slots:
void SetPersistentEditors(const QModelIndex& rkIndex);
};
#endif // CPROPERTYVIEW_H

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<struct name="AnimationParameters" type="single">
<property ID="0x00" name="AnimSet" type="file" extensions="ANCS"/>
<property ID="0x01" name="Node" type="long"/>
<property ID="0x02" name="ANCS int 2" type="long"/>
</struct>

View File

@ -6893,7 +6893,7 @@
<property ID="0xEF5671D6" name="Unknown"/>
<property ID="0xEF582BD6" name="Unknown"/>
<property ID="0xEF5AA575" name="Unknown"/>
<property ID="0xEF5C94E9" name="Unknown"/>
<property ID="0xEF5C94E9" name="Sequence Connections"/>
<property ID="0xEF6D8C96" name="Unknown"/>
<property ID="0xEF6D8F65" name="Unknown"/>
<property ID="0xEF7A8E16" name="Unknown"/>

View File

@ -5,7 +5,16 @@
<struct ID="0x255A4580" template="Structs/EditorProperties.xml"/>
<array ID="0xEF5C94E9">
<default>0</default>
<properties/>
<element_name>Connection</element_name>
<properties>
<property ID="0x00" name="Connection Index" type="short" />
<array ID="0x01" name="Activation Times">
<properties>
<property ID="0x00" name="Time" type="float" />
</properties>
</array>
<property ID="0x02" name="Unknown" type="bool" />
</properties>
</array>
<property ID="0xB8BD2175" type="float">
<default>0.0</default>