Added support for converting some property types to other types
This commit is contained in:
parent
95d270cde7
commit
7dcfda78ba
|
@ -1060,6 +1060,16 @@ public:
|
|||
return (Chr >= CHAR_LITERAL('a') && Chr <= CHAR_LITERAL('z')) ? Chr - 0x20 : Chr;
|
||||
}
|
||||
|
||||
static bool IsVowel(CharType Chr)
|
||||
{
|
||||
Chr = CharToUpper(Chr);
|
||||
return (Chr == 'A' ||
|
||||
Chr == 'E' ||
|
||||
Chr == 'I' ||
|
||||
Chr == 'O' ||
|
||||
Chr == 'U');
|
||||
}
|
||||
|
||||
static bool IsWhitespace(CharType Chr)
|
||||
{
|
||||
return ( (Chr == CHAR_LITERAL('\t')) ||
|
||||
|
|
|
@ -369,12 +369,13 @@ void ChangeTypeName(IProperty* pProperty, const char* pkOldTypeName, const char*
|
|||
SNameKey NewKey(NewTypeHash, pProperty->ID());
|
||||
|
||||
// Disassociate this property from the old mapping.
|
||||
bool WasRegistered = false;
|
||||
auto Find = gNameMap.find(OldKey);
|
||||
|
||||
if (Find != gNameMap.end())
|
||||
{
|
||||
SNameValue& Value = Find->second;
|
||||
NBasics::ListRemoveOne(Value.PropertyList, pProperty);
|
||||
WasRegistered = NBasics::ListRemoveOne(Value.PropertyList, pProperty);
|
||||
}
|
||||
|
||||
// Create a key for the new property and add it to the list.
|
||||
|
@ -389,7 +390,11 @@ void ChangeTypeName(IProperty* pProperty, const char* pkOldTypeName, const char*
|
|||
Find = gNameMap.find(NewKey);
|
||||
}
|
||||
ASSERT(Find != gNameMap.end());
|
||||
Find->second.PropertyList.push_back(pProperty);
|
||||
|
||||
if (WasRegistered)
|
||||
{
|
||||
Find->second.PropertyList.push_back(pProperty);
|
||||
}
|
||||
|
||||
gMapIsDirty = true;
|
||||
}
|
||||
|
|
|
@ -99,6 +99,11 @@ public:
|
|||
mValues = pOtherEnum->mValues;
|
||||
}
|
||||
|
||||
virtual TString ValueAsString(void* pData) const
|
||||
{
|
||||
return TString::FromInt32( Value(pData), 0, 10 );
|
||||
}
|
||||
|
||||
void AddValue(TString ValueName, u32 ValueID)
|
||||
{
|
||||
mValues.push_back( SEnumValue(ValueName, ValueID) );
|
||||
|
|
|
@ -37,6 +37,11 @@ void CFlagsProperty::InitFromArchetype(IProperty* pOther)
|
|||
mAllFlags = pOtherFlags->mAllFlags;
|
||||
}
|
||||
|
||||
TString CFlagsProperty::ValueAsString(void* pData) const
|
||||
{
|
||||
return TString::FromInt32( Value(pData), 0, 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether there are any unrecognized bits toggled on in the property value.
|
||||
* Returns the mask of any invalid bits. If all bits are valid, returns 0.
|
||||
|
|
|
@ -62,6 +62,7 @@ public:
|
|||
virtual void PostInitialize();
|
||||
virtual void SerializeValue(void* pData, IArchive& rArc) const;
|
||||
virtual void InitFromArchetype(IProperty* pOther);
|
||||
virtual TString ValueAsString(void* pData) const;
|
||||
|
||||
/**
|
||||
* Checks whether there are any unrecognized bits toggled on in the property value.
|
||||
|
|
|
@ -393,6 +393,123 @@ void IProperty::ClearDirtyFlag()
|
|||
}
|
||||
}
|
||||
|
||||
bool IProperty::ConvertType(EPropertyType NewType, IProperty* pNewArchetype /*= nullptr*/)
|
||||
{
|
||||
if (mpArchetype && !pNewArchetype)
|
||||
{
|
||||
// We need to start from the root archetype and cascade down sub-instances.
|
||||
// The archetype will re-call this function with a valid pNewArchetype pointer.
|
||||
return mpArchetype->ConvertType(NewType, nullptr);
|
||||
}
|
||||
|
||||
IProperty* pNewProperty = Create(NewType, Game());
|
||||
|
||||
// We can only replace properties with types that have the same size and alignment
|
||||
if( pNewProperty->DataSize() != DataSize() || pNewProperty->DataAlignment() != DataAlignment() )
|
||||
{
|
||||
delete pNewProperty;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use InitFromArchetype to copy most parameters over from the original property.
|
||||
// Note we do *not* want to call the virtual version, because the new property isn't
|
||||
// actually the same type, so the virtual overrides will likely crash.
|
||||
pNewProperty->IProperty::InitFromArchetype(this);
|
||||
pNewProperty->mpArchetype = pNewArchetype;
|
||||
NBasics::VectorRemoveOne(mSubInstances, pNewProperty);
|
||||
|
||||
if( pNewArchetype )
|
||||
{
|
||||
pNewArchetype->mSubInstances.push_back(pNewProperty);
|
||||
}
|
||||
|
||||
// We use CopyDefaultValueTo to ensure that the default value is preserved (as the default value
|
||||
// is important in most games, and necessary to cook correctly in DKCR). However, note that
|
||||
// other type-specific parameters (such as min/max values) are lost in the conversion.
|
||||
CopyDefaultValueTo(pNewProperty);
|
||||
|
||||
// Since we are about to delete this property, we need to unregister it and all its sub-instances
|
||||
// from the name map, and change the type name. The reason we need to do it this way is because
|
||||
// after we change the type name in the map, we won't be able to unregister the original properties
|
||||
// because their type name won't match what's in the map. However, the change has to be done before
|
||||
// initializing any new properties, or else they won't be able to initialize correctly, as the
|
||||
// name won't be tracked in the map under the new type name. So we need to manually unregister
|
||||
// everything to clear the original properties from the map, then change the type name, and then
|
||||
// we're free to start creating and initializing new properties.
|
||||
if (IsRootArchetype() && mGame >= EGame::EchoesDemo)
|
||||
{
|
||||
std::list<IProperty*> SubInstances;
|
||||
GatherAllSubInstances(SubInstances, true);
|
||||
|
||||
for (auto Iter = SubInstances.begin(); Iter != SubInstances.end(); Iter++)
|
||||
{
|
||||
IProperty* pProperty = *Iter;
|
||||
|
||||
if (pProperty->UsesNameMap())
|
||||
{
|
||||
NPropertyMap::UnregisterProperty(pProperty);
|
||||
}
|
||||
}
|
||||
|
||||
NPropertyMap::ChangeTypeName(this, HashableTypeName(), pNewProperty->HashableTypeName());
|
||||
}
|
||||
|
||||
// Swap out our parent's reference to us to point to the new property.
|
||||
if (mpParent)
|
||||
{
|
||||
for (u32 SiblingIdx = 0; SiblingIdx < mpParent->mChildren.size(); SiblingIdx++)
|
||||
{
|
||||
IProperty* pSibling = mpParent->mChildren[SiblingIdx];
|
||||
if (pSibling == this)
|
||||
{
|
||||
mpParent->mChildren[SiblingIdx] = pNewProperty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change all our child properties to be parented under the new property. (Is this adoption?)
|
||||
for (u32 ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
|
||||
{
|
||||
mChildren[ChildIdx]->mpParent = pNewProperty;
|
||||
pNewProperty->mChildren.push_back(mChildren[ChildIdx]);
|
||||
}
|
||||
ASSERT( pNewProperty->mChildren.size() == mChildren.size() );
|
||||
mChildren.clear();
|
||||
|
||||
// Create new versions of all sub-instances that inherit from the new property.
|
||||
// Note that when the sub-instances complete their conversion, they delete themselves.
|
||||
// The IProperty destructor removes the property from the archetype's sub-instance list.
|
||||
// So we shouldn't use a for loop, instead we should just wait until the array is empty
|
||||
u32 SubCount = mSubInstances.size();
|
||||
|
||||
while (!mSubInstances.empty())
|
||||
{
|
||||
bool SubSuccess = mSubInstances[0]->ConvertType(NewType, pNewProperty);
|
||||
ASSERT( SubSuccess );
|
||||
}
|
||||
ASSERT( pNewProperty->mSubInstances.size() == SubCount );
|
||||
|
||||
// Conversion is complete! Initialize the new property and flag it dirty.
|
||||
pNewProperty->Initialize( mpParent, mpScriptTemplate, mOffset );
|
||||
pNewProperty->MarkDirty();
|
||||
|
||||
// Finally, if we are done converting this property and all its instances, resave the templates.
|
||||
if (IsRootArchetype())
|
||||
{
|
||||
NGameList::SaveTemplates();
|
||||
|
||||
if (mGame >= EGame::EchoesDemo)
|
||||
{
|
||||
NPropertyMap::SaveMap(true);
|
||||
}
|
||||
}
|
||||
|
||||
// We're done!
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IProperty::UsesNameMap()
|
||||
{
|
||||
return Game() >= EGame::EchoesDemo &&
|
||||
|
@ -440,7 +557,7 @@ bool IProperty::HasAccurateName()
|
|||
return mFlags.HasFlag( EPropertyFlag::HasCorrectPropertyName );
|
||||
}
|
||||
|
||||
/** IPropertyNew Accessors */
|
||||
/** IProperty Accessors */
|
||||
EGame IProperty::Game() const
|
||||
{
|
||||
return mGame;
|
||||
|
|
|
@ -178,7 +178,8 @@ public:
|
|||
virtual void SerializeValue(void* pData, IArchive& Arc) const = 0;
|
||||
|
||||
virtual void PostInitialize() {}
|
||||
virtual void PropertyValueChanged(void* pPropertyData) {}
|
||||
virtual void PropertyValueChanged(void* pPropertyData) {}
|
||||
virtual void CopyDefaultValueTo(IProperty* pOtherProperty) {}
|
||||
virtual bool IsNumericalType() const { return false; }
|
||||
virtual bool IsPointerType() const { return false; }
|
||||
virtual TString ValueAsString(void* pData) const { return ""; }
|
||||
|
@ -201,6 +202,7 @@ public:
|
|||
void SetSuffix(const TString& rkNewSuffix);
|
||||
void MarkDirty();
|
||||
void ClearDirtyFlag();
|
||||
bool ConvertType(EPropertyType NewType, IProperty* pNewArchetype = nullptr);
|
||||
bool UsesNameMap();
|
||||
bool HasAccurateName();
|
||||
|
||||
|
@ -228,6 +230,7 @@ public:
|
|||
inline bool IsIntrinsic() const { return mFlags.HasFlag(EPropertyFlag::IsIntrinsic); }
|
||||
inline bool IsDirty() const { return mFlags.HasFlag(EPropertyFlag::IsDirty); }
|
||||
inline bool IsRootParent() const { return mpParent == nullptr; }
|
||||
inline bool IsRootArchetype() const { return mpArchetype == nullptr; }
|
||||
|
||||
/** Create */
|
||||
static IProperty* Create(EPropertyType Type,
|
||||
|
@ -375,6 +378,16 @@ public:
|
|||
mDefaultValue = static_cast<TTypedProperty*>(pOther)->mDefaultValue;
|
||||
}
|
||||
|
||||
virtual void CopyDefaultValueTo(IProperty* pOtherProperty)
|
||||
{
|
||||
// WARNING: We don't do any type checking here because this function is used for type conversion,
|
||||
// which necessitates that the property class is allowed to be different. The underlying type is
|
||||
// assumed to be the same. It is the caller's responsibility to ensure this function is not called
|
||||
// with incompatible property types.
|
||||
TTypedProperty* pTypedOther = static_cast<TTypedProperty*>(pOtherProperty);
|
||||
pTypedOther->mDefaultValue = mDefaultValue;
|
||||
}
|
||||
|
||||
inline PropType* ValuePtr(void* pData) const
|
||||
{
|
||||
return (PropType*) RawValuePtr(pData);
|
||||
|
|
|
@ -89,7 +89,7 @@ typedef TPropertyRef<CSequenceProperty> CSequenceRef;
|
|||
typedef TPropertyRef<CSplineProperty> CSplineRef;
|
||||
typedef TPropertyRef<CGuidProperty> CGuidRef;
|
||||
typedef TPropertyRef<CPointerProperty> CPointerRef;
|
||||
typedef TPropertyRef<CStructProperty> CStructRef;
|
||||
typedef TPropertyRef<CStructProperty> CStructRef;
|
||||
typedef TPropertyRef<CArrayProperty> CArrayRef;
|
||||
|
||||
/** Special version for enums */
|
||||
|
|
|
@ -53,7 +53,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
|
|||
|
||||
if (pProp)
|
||||
{
|
||||
EPropertyType Type = GetEffectiveFieldType(pProp);
|
||||
EPropertyType Type = mpModel->GetEffectiveFieldType(pProp);
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
|
@ -168,7 +168,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
|
|||
else if (rkIndex.internalId() & 0x80000000)
|
||||
{
|
||||
pProp = mpModel->PropertyForIndex(rkIndex, true);
|
||||
EPropertyType Type = GetEffectiveFieldType(pProp);
|
||||
EPropertyType Type = mpModel->GetEffectiveFieldType(pProp);
|
||||
|
||||
// Handle character
|
||||
if (Type == EPropertyType::AnimationSet)
|
||||
|
@ -208,7 +208,7 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
|
|||
{
|
||||
if (!mEditInProgress)
|
||||
{
|
||||
EPropertyType Type = pProp->Type();
|
||||
EPropertyType Type = mpModel->GetEffectiveFieldType(pProp);
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
|
@ -240,7 +240,8 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
|
|||
|
||||
if (!pSpinBox->hasFocus())
|
||||
{
|
||||
CIntProperty *pInt = TPropCast<CIntProperty>(pProp);
|
||||
// Ints use static_cast since sometimes we treat other property types as ints
|
||||
CIntProperty *pInt = static_cast<CIntProperty*>(pProp);
|
||||
pSpinBox->setValue( pInt->Value(pData) );
|
||||
}
|
||||
|
||||
|
@ -334,7 +335,7 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
|
|||
else if (rkIndex.internalId() & 0x80000000)
|
||||
{
|
||||
pProp = mpModel->PropertyForIndex(rkIndex, true);
|
||||
EPropertyType Type = GetEffectiveFieldType(pProp);
|
||||
EPropertyType Type = mpModel->GetEffectiveFieldType(pProp);
|
||||
|
||||
if (Type == EPropertyType::AnimationSet)
|
||||
SetCharacterEditorData(pEditor, rkIndex);
|
||||
|
@ -364,7 +365,7 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
|||
|
||||
if (pProp)
|
||||
{
|
||||
EPropertyType Type = GetEffectiveFieldType(pProp);
|
||||
EPropertyType Type = mpModel->GetEffectiveFieldType(pProp);
|
||||
|
||||
QVector<CScriptObject*> Objects;
|
||||
Objects << mpModel->GetScriptObject();
|
||||
|
@ -417,6 +418,7 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
|||
|
||||
case EPropertyType::Int:
|
||||
{
|
||||
// Ints use static_cast since sometimes we treat other property types as ints
|
||||
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
||||
CIntProperty* pInt = static_cast<CIntProperty*>(pProp);
|
||||
pInt->ValueRef(pData) = pSpinBox->value();
|
||||
|
@ -675,46 +677,6 @@ EPropertyType CPropertyDelegate::DetermineCharacterPropType(EGame Game, const QM
|
|||
return EPropertyType::Invalid;
|
||||
}
|
||||
|
||||
/** Determine the effective property type to use. Allows some types to be treated as other types. */
|
||||
EPropertyType CPropertyDelegate::GetEffectiveFieldType(IProperty* pProperty) const
|
||||
{
|
||||
EPropertyType Out = pProperty->Type();
|
||||
|
||||
switch (Out)
|
||||
{
|
||||
|
||||
// Allow Choice/Enum properties to be edited as Int properties if they don't have any values set.
|
||||
case EPropertyType::Choice:
|
||||
case EPropertyType::Enum:
|
||||
{
|
||||
CChoiceProperty* pChoice = TPropCast<CChoiceProperty>(pProperty);
|
||||
|
||||
if (pChoice->NumPossibleValues() == 0)
|
||||
{
|
||||
Out = EPropertyType::Int;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Same deal with Flag properties
|
||||
case EPropertyType::Flags:
|
||||
{
|
||||
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProperty);
|
||||
|
||||
if (pFlags->NumFlags() == 0)
|
||||
{
|
||||
Out = EPropertyType::Int;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Out;
|
||||
}
|
||||
|
||||
// ************ PUBLIC SLOTS ************
|
||||
void CPropertyDelegate::WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex)
|
||||
{
|
||||
|
|
|
@ -29,7 +29,6 @@ public:
|
|||
void SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const;
|
||||
void SetCharacterModelData(QWidget *pEditor, const QModelIndex& rkIndex) const;
|
||||
EPropertyType DetermineCharacterPropType(EGame Game, const QModelIndex& rkIndex) const;
|
||||
EPropertyType GetEffectiveFieldType(IProperty* pProperty) const;
|
||||
|
||||
public slots:
|
||||
void WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex);
|
||||
|
|
|
@ -321,8 +321,9 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
|
|||
if (rkIndex.column() == 1)
|
||||
{
|
||||
void* pData = DataPointerForIndex(rkIndex);
|
||||
EPropertyType Type = GetEffectiveFieldType(pProp);
|
||||
|
||||
switch (pProp->Type())
|
||||
switch (Type)
|
||||
{
|
||||
// Enclose vector property text in parentheses
|
||||
case EPropertyType::Vector:
|
||||
|
@ -620,6 +621,46 @@ void CPropertyModel::ClearSlot(int ID)
|
|||
mFirstUnusedID = ID;
|
||||
}
|
||||
|
||||
/** Determine the effective property type to use. Allows some types to be treated as other types. */
|
||||
EPropertyType CPropertyModel::GetEffectiveFieldType(IProperty* pProperty) const
|
||||
{
|
||||
EPropertyType Out = pProperty->Type();
|
||||
|
||||
switch (Out)
|
||||
{
|
||||
|
||||
// Allow Choice/Enum properties to be edited as Int properties if they don't have any values set.
|
||||
case EPropertyType::Choice:
|
||||
case EPropertyType::Enum:
|
||||
{
|
||||
CChoiceProperty* pChoice = TPropCast<CChoiceProperty>(pProperty);
|
||||
|
||||
if (pChoice->NumPossibleValues() == 0)
|
||||
{
|
||||
Out = EPropertyType::Int;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Same deal with Flag properties
|
||||
case EPropertyType::Flags:
|
||||
{
|
||||
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProperty);
|
||||
|
||||
if (pFlags->NumFlags() == 0)
|
||||
{
|
||||
Out = EPropertyType::Int;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Out;
|
||||
}
|
||||
|
||||
void CPropertyModel::SetShowPropertyNameValidity(bool Enable)
|
||||
{
|
||||
mShowNameValidity = Enable;
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
void ResizeArray(const QModelIndex& rkIndex, u32 NewSize);
|
||||
void ClearSlot(int ID);
|
||||
|
||||
EPropertyType GetEffectiveFieldType(IProperty* pProperty) const;
|
||||
void SetShowPropertyNameValidity(bool Enable);
|
||||
|
||||
inline void SetFont(QFont Font) { mFont = Font; }
|
||||
|
|
|
@ -91,7 +91,7 @@ void CPropertyView::SetEditor(CWorldEditor *pEditor)
|
|||
connect(mpEditor, SIGNAL(PropertyModified(CScriptObject*,IProperty*)), mpModel, SLOT(NotifyPropertyModified(CScriptObject*,IProperty*)));
|
||||
}
|
||||
|
||||
void CPropertyView::SetProperties(CStructRef InProperties)
|
||||
void CPropertyView::SetIntrinsicProperties(CStructRef InProperties)
|
||||
{
|
||||
mpObject = nullptr;
|
||||
mpModel->SetBoldModifiedProperties(false); // todo, we prob want this, but can't set default properties on non script yet
|
||||
|
@ -190,12 +190,17 @@ void CPropertyView::SetPersistentEditors(const QModelIndex& rkParent)
|
|||
switch (Type)
|
||||
{
|
||||
case EPropertyType::Bool:
|
||||
case EPropertyType::Enum:
|
||||
case EPropertyType::Choice:
|
||||
case EPropertyType::Color:
|
||||
case EPropertyType::Asset:
|
||||
openPersistentEditor(ChildIndex);
|
||||
break;
|
||||
|
||||
case EPropertyType::Enum:
|
||||
case EPropertyType::Choice:
|
||||
if (TPropCast<CEnumProperty>(pProp)->NumPossibleValues() > 0)
|
||||
openPersistentEditor(ChildIndex);
|
||||
break;
|
||||
|
||||
case EPropertyType::Struct:
|
||||
setFirstColumnSpanned(iChild, rkParent, true);
|
||||
break;
|
||||
|
@ -232,6 +237,11 @@ void CPropertyView::OnPropertyModified(const QModelIndex& rkIndex)
|
|||
}
|
||||
}
|
||||
|
||||
void CPropertyView::RefreshView()
|
||||
{
|
||||
SetInstance(mpObject);
|
||||
}
|
||||
|
||||
void CPropertyView::CreateContextMenu(const QPoint& rkPos)
|
||||
{
|
||||
QModelIndex Index = indexAt(rkPos);
|
||||
|
@ -286,6 +296,7 @@ void CPropertyView::ToggleShowNameValidity(bool ShouldShow)
|
|||
void CPropertyView::EditPropertyTemplate()
|
||||
{
|
||||
CTemplateEditDialog Dialog(mpMenuProperty, mpEditor);
|
||||
connect(&Dialog, SIGNAL(PerformedTypeConversion()), this, SLOT(RefreshView()));
|
||||
Dialog.exec();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
void setModel(QAbstractItemModel *pModel);
|
||||
bool event(QEvent *pEvent);
|
||||
void SetEditor(CWorldEditor *pEditor);
|
||||
void SetProperties(CStructRef InProperties);
|
||||
void SetIntrinsicProperties(CStructRef InProperties);
|
||||
void SetInstance(CScriptObject *pObj);
|
||||
void UpdateEditorProperties(const QModelIndex& rkParent);
|
||||
|
||||
|
@ -38,6 +38,7 @@ public slots:
|
|||
void ClosePersistentEditors(const QModelIndex& rkIndex);
|
||||
void OnPropertyModified(const QModelIndex& rkIndex);
|
||||
|
||||
void RefreshView();
|
||||
void CreateContextMenu(const QPoint& rkPos);
|
||||
void ToggleShowNameValidity(bool ShouldShow);
|
||||
void EditPropertyTemplate();
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <Core/Resource/Script/NGameList.h>
|
||||
#include <Core/Resource/Script/NPropertyMap.h>
|
||||
|
||||
#include <QMenu>
|
||||
|
||||
CTemplateEditDialog::CTemplateEditDialog(IProperty *pProperty, QWidget *pParent)
|
||||
: QDialog(pParent)
|
||||
, mpUI(new Ui::CTemplateEditDialog)
|
||||
|
@ -55,6 +57,21 @@ CTemplateEditDialog::CTemplateEditDialog(IProperty *pProperty, QWidget *pParent)
|
|||
}
|
||||
RefreshTypeNameOverride();
|
||||
|
||||
// Configure convert button
|
||||
if (Type == EPropertyType::Int || Type == EPropertyType::Choice || Type == EPropertyType::Flags || Type == EPropertyType::Sound)
|
||||
{
|
||||
QMenu* pConvertMenu = new QMenu(this);
|
||||
if (Type != EPropertyType::Int) pConvertMenu->addAction("Int", this, SLOT(ConvertToInt()));
|
||||
if (Type != EPropertyType::Choice) pConvertMenu->addAction("Choice", this, SLOT(ConvertToChoice()));
|
||||
if (Type != EPropertyType::Flags) pConvertMenu->addAction("Flags", this, SLOT(ConvertToFlags()));
|
||||
if (Type != EPropertyType::Sound) pConvertMenu->addAction("Sound", this, SLOT(ConvertToSound()));
|
||||
mpUI->TypeConversionButton->setMenu(pConvertMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
mpUI->TypeConversionWidget->setHidden(true);
|
||||
}
|
||||
|
||||
// Hide templates list for MP1
|
||||
if (mGame <= EGame::Prime)
|
||||
{
|
||||
|
@ -156,6 +173,52 @@ void CTemplateEditDialog::RefreshTypeNameOverride()
|
|||
}
|
||||
}
|
||||
|
||||
void CTemplateEditDialog::ConvertPropertyType(EPropertyType Type)
|
||||
{
|
||||
const char* pkCurType = TEnumReflection<EPropertyType>::ConvertValueToString(mpProperty->Type());
|
||||
const char* pkNewType = TEnumReflection<EPropertyType>::ConvertValueToString(Type);
|
||||
|
||||
if (
|
||||
UICommon::YesNoQuestion(this, "Warning",
|
||||
QString("You are converting %1 %2 property to %3. This cannot be undone. Are you sure?")
|
||||
.arg( TString::IsVowel(pkCurType[0]) ? "an" : "a" )
|
||||
.arg( pkCurType )
|
||||
.arg( pkNewType ) )
|
||||
)
|
||||
{
|
||||
if( mpProperty->ConvertType(Type) )
|
||||
{
|
||||
mpProperty = nullptr;
|
||||
emit PerformedTypeConversion();
|
||||
close();
|
||||
}
|
||||
else
|
||||
{
|
||||
UICommon::ErrorMsg(this, "Type conversion failed; conversion between these types is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTemplateEditDialog::ConvertToInt()
|
||||
{
|
||||
ConvertPropertyType( EPropertyType::Int );
|
||||
}
|
||||
|
||||
void CTemplateEditDialog::ConvertToChoice()
|
||||
{
|
||||
ConvertPropertyType( EPropertyType::Choice );
|
||||
}
|
||||
|
||||
void CTemplateEditDialog::ConvertToSound()
|
||||
{
|
||||
ConvertPropertyType( EPropertyType::Sound );
|
||||
}
|
||||
|
||||
void CTemplateEditDialog::ConvertToFlags()
|
||||
{
|
||||
ConvertPropertyType( EPropertyType::Flags );
|
||||
}
|
||||
|
||||
// ************ PROTECTED ************
|
||||
void CTemplateEditDialog::UpdateDescription(const TString& rkNewDesc)
|
||||
{
|
||||
|
|
|
@ -32,10 +32,20 @@ public:
|
|||
CTemplateEditDialog(IProperty* pProperty, QWidget *pParent = 0);
|
||||
~CTemplateEditDialog();
|
||||
|
||||
signals:
|
||||
void PerformedTypeConversion();
|
||||
|
||||
public slots:
|
||||
void ApplyChanges();
|
||||
void RefreshTypeNameOverride();
|
||||
|
||||
protected slots:
|
||||
void ConvertPropertyType(EPropertyType Type);
|
||||
void ConvertToInt();
|
||||
void ConvertToChoice();
|
||||
void ConvertToSound();
|
||||
void ConvertToFlags();
|
||||
|
||||
protected:
|
||||
void UpdateDescription(const TString& rkNewDesc);
|
||||
void UpdateTypeName(const TString& kNewTypeName, bool AllowOverride);
|
||||
|
|
|
@ -170,6 +170,44 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="TypeConversionWidget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>221</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="TypeConversionButton">
|
||||
<property name="text">
|
||||
<string>Convert to...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="TemplatesGroupBox">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
@ -6045,6 +6045,10 @@
|
|||
<Key ID="0x28F49A53" Type="VolcanoBossBodyPartStructA"/>
|
||||
<Value Name="VolcanoBossBodyPartStructA"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x28F82261" Type="choice"/>
|
||||
<Value Name="SoftwareChannel"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x28F82261" Type="int"/>
|
||||
<Value Name="SoftwareChannel"/>
|
||||
|
@ -7617,6 +7621,10 @@
|
|||
<Key ID="0x3343ADE6" Type="int"/>
|
||||
<Value Name="CounterCondition7"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x334A34BB" Type="choice"/>
|
||||
<Value Name="ParticleSystem1Orientation"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x334A34BB" Type="int"/>
|
||||
<Value Name="ParticleSystem1Orientation"/>
|
||||
|
@ -11329,6 +11337,10 @@
|
|||
<Key ID="0x4B106481" Type="float"/>
|
||||
<Value Name="Unknown"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x4B15EB9A" Type="choice"/>
|
||||
<Value Name="ChargeUpgrade"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x4B15EB9A" Type="int"/>
|
||||
<Value Name="ChargeUpgrade"/>
|
||||
|
@ -13917,6 +13929,10 @@
|
|||
<Key ID="0x5D28CCE5" Type="float"/>
|
||||
<Value Name="Unknown"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x5D298A43" Type="choice"/>
|
||||
<Value Name="Unknown"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x5D298A43" Type="int"/>
|
||||
<Value Name="Unknown"/>
|
||||
|
@ -20217,6 +20233,10 @@
|
|||
<Key ID="0x86C887A5" Type="bool"/>
|
||||
<Value Name="Unknown"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x86CF23F4" Type="choice"/>
|
||||
<Value Name="Priority"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x86CF23F4" Type="int"/>
|
||||
<Value Name="Priority"/>
|
||||
|
@ -23617,9 +23637,13 @@
|
|||
<Key ID="0x9DEE347A" Type="int"/>
|
||||
<Value Name="CenterPlank"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x9DFADEE0" Type="choice"/>
|
||||
<Value Name="DeathParticleSystemOrientation"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x9DFADEE0" Type="int"/>
|
||||
<Value Name="Unknown"/>
|
||||
<Value Name="DeathParticleSystemOrientation"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0x9E02691C" Type="sound"/>
|
||||
|
@ -24729,6 +24753,10 @@
|
|||
<Key ID="0xA4EE16BF" Type="sound"/>
|
||||
<Value Name="Sound1"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0xA4EF7B42" Type="sound"/>
|
||||
<Value Name="WarpOutSound"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0xA4EF7B42" Type="int"/>
|
||||
<Value Name="WarpOutSound"/>
|
||||
|
@ -28541,6 +28569,10 @@
|
|||
<Key ID="0xBE5F118D" Type="asset"/>
|
||||
<Value Name="SwoopInterruptedSound"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0xBE73724A" Type="choice"/>
|
||||
<Value Name="Flavor"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0xBE73724A" Type="int"/>
|
||||
<Value Name="Flavor"/>
|
||||
|
@ -32729,6 +32761,10 @@
|
|||
<Key ID="0xD9CA50C2" Type="spline"/>
|
||||
<Value Name="SlideSoundLowPassFilter"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0xD9CCE9D9" Type="choice"/>
|
||||
<Value Name="ParticleSystem2Orientation"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0xD9CCE9D9" Type="int"/>
|
||||
<Value Name="ParticleSystem2Orientation"/>
|
||||
|
@ -35259,7 +35295,7 @@
|
|||
</Element>
|
||||
<Element>
|
||||
<Key ID="0xEA86A2B9" Type="int"/>
|
||||
<Value Name="Charge Combo"/>
|
||||
<Value Name="Unknown"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0xEA870072" Type="UnknownStruct66"/>
|
||||
|
|
|
@ -121,8 +121,8 @@
|
|||
<Element Type="Bool" ID="0x3BDD2FED">
|
||||
<DefaultValue>false</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Int" ID="0x334A34BB">
|
||||
<DefaultValue>0</DefaultValue>
|
||||
<Element Type="Choice" ID="0x334A34BB">
|
||||
<DefaultValue>0x0</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Asset" ID="0xC7493FEE">
|
||||
<TypeFilter>
|
||||
|
@ -142,8 +142,8 @@
|
|||
<Element Type="Bool" ID="0xC98AC215">
|
||||
<DefaultValue>false</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Int" ID="0xD9CCE9D9">
|
||||
<DefaultValue>0</DefaultValue>
|
||||
<Element Type="Choice" ID="0xD9CCE9D9">
|
||||
<DefaultValue>0x0</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Asset" ID="0x979042C8">
|
||||
<TypeFilter>
|
||||
|
@ -157,8 +157,8 @@
|
|||
<Z>1.0</Z>
|
||||
</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Int" ID="0x9DFADEE0">
|
||||
<DefaultValue>0</DefaultValue>
|
||||
<Element Type="Choice" ID="0x9DFADEE0">
|
||||
<DefaultValue>0x0</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Bool" ID="0x2C7B18DD">
|
||||
<DefaultValue>true</DefaultValue>
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
<Name>Kralee</Name>
|
||||
<SubProperties>
|
||||
<Element Type="Struct" ID="0x255A4580" Archetype="EditorProperties"/>
|
||||
<Element Type="Int" ID="0xBE73724A">
|
||||
<DefaultValue>0</DefaultValue>
|
||||
<Element Type="Choice" ID="0xBE73724A">
|
||||
<DefaultValue>0x0</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Struct" ID="0xB3774750" Archetype="PatternedAITypedef">
|
||||
<SubProperties>
|
||||
|
@ -135,7 +135,7 @@
|
|||
<Element Type="Sound" ID="0x80B58324">
|
||||
<DefaultValue>0</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Int" ID="0xA4EF7B42">
|
||||
<Element Type="Sound" ID="0xA4EF7B42">
|
||||
<DefaultValue>-1</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Bool" ID="0xC3CC437F">
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
<Element Type="Int" ID="0xBD9EA266">
|
||||
<DefaultValue>117</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Int" ID="0x86CF23F4">
|
||||
<DefaultValue>1</DefaultValue>
|
||||
<Element Type="Choice" ID="0x86CF23F4">
|
||||
<DefaultValue>0x1</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Bool" ID="0xA00360CC">
|
||||
<DefaultValue>false</DefaultValue>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<DefaultValue>20.0</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Choice" ID="0x68ACBD86">
|
||||
<DefaultValue>0</DefaultValue>
|
||||
<DefaultValue>0x0</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Flags" ID="0x4F7FEC39">
|
||||
<DefaultValue>0</DefaultValue>
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
<Element Type="Int" ID="0x80C66C37">
|
||||
<DefaultValue>127</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Int" ID="0x28F82261">
|
||||
<DefaultValue>0</DefaultValue>
|
||||
<Element Type="Choice" ID="0x28F82261">
|
||||
<DefaultValue>0x0</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Bool" ID="0xD3356FE7">
|
||||
<DefaultValue>true</DefaultValue>
|
||||
|
|
|
@ -72,8 +72,8 @@
|
|||
<Element Type="Int" ID="0xFB33F2A1">
|
||||
<DefaultValue>1</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Int" ID="0x4B15EB9A">
|
||||
<DefaultValue>1</DefaultValue>
|
||||
<Element Type="Choice" ID="0x4B15EB9A">
|
||||
<DefaultValue>0x1</DefaultValue>
|
||||
</Element>
|
||||
<Element Type="Int" ID="0x44FBB19C">
|
||||
<DefaultValue>0</DefaultValue>
|
||||
|
|
Loading…
Reference in New Issue