Fixed a lot of property bugs, fixed more various VS2017 compiler errors, property editor works correctly now

This commit is contained in:
Aruki 2018-07-08 21:59:01 -06:00
parent 6cbc2a3208
commit 4faadbda61
30 changed files with 466 additions and 314 deletions

View File

@ -6,7 +6,7 @@
class CVectorOutStream : public IOutputStream class CVectorOutStream : public IOutputStream
{ {
static const u32 skAllocSize = 1024; // must be power of 2 static const u32 skAllocSize = 1; // must be 1 or a power of 2
std::vector<char> *mpVector; std::vector<char> *mpVector;
bool mOwnsVector; bool mOwnsVector;

View File

@ -932,7 +932,46 @@ public:
static _TString FromFloat(float Value, int MinDecimals = 1) static _TString FromFloat(float Value, int MinDecimals = 1)
{ {
return Format("%f.*", Value, MinDecimals); // Initial float -> string conversion
std::basic_stringstream<CharType> SStream;
if (MinDecimals > 0) SStream.setf(std::ios_base::showpoint);
SStream.setf(std::ios_base::fixed, std::ios_base::floatfield);
SStream << Value;
_TString Out = SStream.str();
// Make sure we have the right number of decimals
int DecIdx = Out.IndexOf(CHAR_LITERAL('.'));
if (DecIdx == -1 && MinDecimals > 0)
{
DecIdx = Out.Size();
Out.Append(CHAR_LITERAL('.'));
}
int NumZeroes = (DecIdx == -1 ? 0 : Out.Size() - (DecIdx + 1));
// Add extra zeroes to meet the minimum decimal count
if (NumZeroes < MinDecimals)
{
for (int iDec = 0; iDec < (MinDecimals - NumZeroes); iDec++)
Out.Append(CHAR_LITERAL('.'));
}
// Remove unnecessary trailing zeroes from the end of the string
else if (NumZeroes > MinDecimals)
{
while (Out.Back() == CHAR_LITERAL('0') && NumZeroes > MinDecimals && NumZeroes > 0)
{
Out = Out.ChopBack(1);
NumZeroes--;
}
// Remove decimal point
if (NumZeroes == 0)
Out = Out.ChopBack(1);
}
return Out;
} }
static _TString FileSizeString(u64 Size, u32 NumDecimals = 2) static _TString FileSizeString(u64 Size, u32 NumDecimals = 2)

View File

@ -112,7 +112,7 @@ public:
inline void SetOptions(FMaterialOptions Options) { mOptions = Options; Update(); } inline void SetOptions(FMaterialOptions Options) { mOptions = Options; Update(); }
inline void SetVertexDescription(FVertexDescription Desc) { mVtxDesc = Desc; Update(); } inline void SetVertexDescription(FVertexDescription Desc) { mVtxDesc = Desc; Update(); }
inline void SetBlendMode(GLenum SrcFac, GLenum DstFac) { mBlendSrcFac = SrcFac; mBlendDstFac = DstFac; mRecalcHash = true; } inline void SetBlendMode(GLenum SrcFac, GLenum DstFac) { mBlendSrcFac = SrcFac; mBlendDstFac = DstFac; mRecalcHash = true; }
inline void SetKonst(CColor& Konst, u32 KIndex) { mKonstColors[KIndex] = Konst; Update(); } inline void SetKonst(const CColor& Konst, u32 KIndex) { mKonstColors[KIndex] = Konst; Update(); }
inline void SetIndTexture(CTexture *pTex) { mpIndirectTexture = pTex; } inline void SetIndTexture(CTexture *pTex) { mpIndirectTexture = pTex; }
inline void SetLightingEnabled(bool Enabled) { mLightingEnabled = Enabled; Update(); } inline void SetLightingEnabled(bool Enabled) { mLightingEnabled = Enabled; Update(); }

View File

@ -24,7 +24,7 @@ public:
CVertex() {} CVertex() {}
CVertex(CVector3f& rPos) CVertex(const CVector3f& rPos)
{ {
Position = rPos; Position = rPos;
} }

View File

@ -88,6 +88,9 @@ bool CScriptObject::IsEditorProperty(IPropertyNew *pProp)
(pProp == mScale.Property()) || (pProp == mScale.Property()) ||
(pProp == mActive.Property()) || (pProp == mActive.Property()) ||
(pProp == mLightParameters.Property()) || (pProp == mLightParameters.Property()) ||
(pProp->Parent() == mPosition.Property()) ||
(pProp->Parent() == mRotation.Property()) ||
(pProp->Parent() == mScale.Property()) ||
(pProp->Parent() == mLightParameters.Property()) (pProp->Parent() == mLightParameters.Property())
); );
} }

View File

@ -55,11 +55,6 @@ void IPropertyNew::_CalcOffset()
} }
} }
u32 IPropertyNew::_GetOffset() const
{
return mOffset;
}
void IPropertyNew::_ClearChildren() void IPropertyNew::_ClearChildren()
{ {
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++) for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
@ -118,7 +113,7 @@ void IPropertyNew::InitFromArchetype(IPropertyNew* pOther)
{ {
//@todo maybe somehow use Serialize for this instead? //@todo maybe somehow use Serialize for this instead?
mpArchetype = pOther; mpArchetype = pOther;
mFlags = pOther->mFlags & ~EPropertyFlag::ArchetypeCopyFlags; mFlags = pOther->mFlags & EPropertyFlag::ArchetypeCopyFlags;
mID = pOther->mID; mID = pOther->mID;
mName = pOther->mName; mName = pOther->mName;
mDescription = pOther->mDescription; mDescription = pOther->mDescription;
@ -161,7 +156,8 @@ void* IPropertyNew::RawValuePtr(void* pData) const
return pData; return pData;
void* pBasePtr = (mpPointerParent ? mpPointerParent->GetChildDataPointer(pData) : pData); void* pBasePtr = (mpPointerParent ? mpPointerParent->GetChildDataPointer(pData) : pData);
return ((char*)pBasePtr + mOffset); void* pValuePtr = ((char*)pBasePtr + mOffset);
return pValuePtr;
} }
IPropertyNew* IPropertyNew::ChildByID(u32 ID) const IPropertyNew* IPropertyNew::ChildByID(u32 ID) const
@ -342,8 +338,7 @@ IPropertyNew* IPropertyNew::Create(EPropertyTypeNew Type,
} }
IPropertyNew* IPropertyNew::CreateCopy(IPropertyNew* pArchetype, IPropertyNew* IPropertyNew::CreateCopy(IPropertyNew* pArchetype,
IPropertyNew* pParent, IPropertyNew* pParent)
bool CallPostInit /*= true*/)
{ {
// Note this is mainly going to be used to create copies from struct/enum/flag archetype properties. // Note this is mainly going to be used to create copies from struct/enum/flag archetype properties.
// Properties that have archetypes will never be the root property of a script template, and there // Properties that have archetypes will never be the root property of a script template, and there
@ -354,11 +349,5 @@ IPropertyNew* IPropertyNew::CreateCopy(IPropertyNew* pArchetype,
IPropertyNew* pOut = Create(pArchetype->Type(), pParent, pParent->mpMasterTemplate, pParent->mpScriptTemplate, false); IPropertyNew* pOut = Create(pArchetype->Type(), pParent, pParent->mpMasterTemplate, pParent->mpScriptTemplate, false);
pOut->InitFromArchetype(pArchetype); pOut->InitFromArchetype(pArchetype);
pArchetype->mSubInstances.push_back(pOut); pArchetype->mSubInstances.push_back(pOut);
if (CallPostInit)
{
pOut->PostInitialize();
}
return pOut; return pOut;
} }

View File

@ -157,7 +157,6 @@ protected:
/** Private constructor - use static methods to instantiate */ /** Private constructor - use static methods to instantiate */
IPropertyNew(); IPropertyNew();
void _CalcOffset(); void _CalcOffset();
u32 _GetOffset() const;
void _ClearChildren(); void _ClearChildren();
/** Called after property is created and fully initialized */ /** Called after property is created and fully initialized */
@ -213,6 +212,7 @@ public:
inline TString Description() const; inline TString Description() const;
inline TString Suffix() const; inline TString Suffix() const;
inline TIDString IDString(bool FullyQualified) const; inline TIDString IDString(bool FullyQualified) const;
inline u32 Offset() const;
inline u32 ID() const; inline u32 ID() const;
inline bool IsArchetype() const { return mFlags.HasFlag(EPropertyFlag::IsArchetype); } inline bool IsArchetype() const { return mFlags.HasFlag(EPropertyFlag::IsArchetype); }
@ -227,8 +227,7 @@ public:
bool CallPostInit = true); bool CallPostInit = true);
static IPropertyNew* CreateCopy(IPropertyNew* pArchetype, static IPropertyNew* CreateCopy(IPropertyNew* pArchetype,
IPropertyNew* pParent, IPropertyNew* pParent);
bool CallPostInit = true);
}; };
inline ECookPreferenceNew IPropertyNew::CookPreference() const inline ECookPreferenceNew IPropertyNew::CookPreference() const
@ -298,12 +297,17 @@ inline TString IPropertyNew::Suffix() const
inline TString IPropertyNew::IDString(bool FullyQualified) const inline TString IPropertyNew::IDString(bool FullyQualified) const
{ {
if (FullyQualified && mpParent != nullptr) if (FullyQualified && mpParent != nullptr && mpParent->Parent() != nullptr)
return mpParent->IDString(FullyQualified) + ":" + TString::HexString(mID); return mpParent->IDString(FullyQualified) + ":" + TString::HexString(mID);
else else
return TString::HexString(mID); return TString::HexString(mID);
} }
inline u32 IPropertyNew::Offset() const
{
return mOffset;
}
inline u32 IPropertyNew::ID() const inline u32 IPropertyNew::ID() const
{ {
return mID; return mID;

View File

@ -24,8 +24,9 @@ class CArrayProperty : public TTypedPropertyNew<int, EPropertyTypeNew::Array>
{ {
friend class CTemplateLoader; friend class CTemplateLoader;
/** This class inherits from TTypedPropertyNew<int> in order to expose the array /** This class inherits from TTypedPropertyNew<int> in order to expose the array
* count value. Outside users can edit this value and we respond by updating the * count value (the first member of SScriptArray). Outside users can edit this
* allocated space, handling destruction/construction, etc. * value and we respond by updating the allocated space, handling item destruction
* and construction, etc.
*/ */
IPropertyNew* mpItemArchetype; IPropertyNew* mpItemArchetype;
@ -99,7 +100,7 @@ public:
virtual void SerializeValue(void* pData, IArchive& Arc) const virtual void SerializeValue(void* pData, IArchive& Arc) const
{ {
u32 Count = ArrayCount(pData); u32 Count = ArrayCount(pData);
Arc.SerializePrimitive(Count); Arc.SerializeContainerSize(Count, "ArrayElement");
if (Arc.IsReader()) if (Arc.IsReader())
Resize(pData, Count); Resize(pData, Count);
@ -115,6 +116,13 @@ public:
} }
} }
virtual void InitFromArchetype(IPropertyNew* pOther)
{
TTypedPropertyNew::InitFromArchetype(pOther);
CArrayProperty* pOtherArray = static_cast<CArrayProperty*>(pOther);
mpItemArchetype = IPropertyNew::CreateCopy(pOtherArray->mpItemArchetype, this);
}
u32 ArrayCount(void* pPropertyData) const u32 ArrayCount(void* pPropertyData) const
{ {
return ValueRef(pPropertyData); return ValueRef(pPropertyData);

View File

@ -18,6 +18,12 @@ public:
} }
#endif #endif
virtual void InitFromArchetype(IPropertyNew* pOther)
{
TTypedPropertyNew::InitFromArchetype(pOther);
mTypeFilter = static_cast<CAssetProperty*>(pOther)->mTypeFilter;
}
virtual void SerializeValue(void* pData, IArchive& Arc) const virtual void SerializeValue(void* pData, IArchive& Arc) const
{ {
Arc.SerializePrimitive( ValueRef(pData) ); Arc.SerializePrimitive( ValueRef(pData) );

View File

@ -46,6 +46,13 @@ public:
Arc.SerializePrimitive( (u32&) ValueRef(pData) ); Arc.SerializePrimitive( (u32&) ValueRef(pData) );
} }
virtual void InitFromArchetype(IPropertyNew* pOther)
{
TTypedPropertyNew::InitFromArchetype(pOther);
TEnumPropertyBase* pOtherEnum = static_cast<TEnumPropertyBase*>(pOther);
mValues = pOtherEnum->mValues;
}
virtual TString GetTemplateFileName() virtual TString GetTemplateFileName()
{ {
ASSERT(IsArchetype() || mpArchetype); ASSERT(IsArchetype() || mpArchetype);

View File

@ -75,11 +75,30 @@ public:
} }
#endif #endif
virtual void PostInitialize()
{
TTypedPropertyNew::PostInitialize();
// Create AllFlags mask
mAllFlags = 0;
for (int FlagIdx = 0; FlagIdx < mBitFlags.size(); FlagIdx++)
mAllFlags |= mBitFlags[FlagIdx].Mask;
}
virtual void SerializeValue(void* pData, IArchive& rArc) const virtual void SerializeValue(void* pData, IArchive& rArc) const
{ {
rArc.SerializeHexPrimitive( (u32&) ValueRef(pData) ); rArc.SerializeHexPrimitive( (u32&) ValueRef(pData) );
} }
virtual void InitFromArchetype(IPropertyNew* pOther)
{
TTypedPropertyNew::InitFromArchetype(pOther);
CFlagsProperty* pOtherFlags = static_cast<CFlagsProperty*>(pOther);
mBitFlags = pOtherFlags->mBitFlags;
mAllFlags = pOtherFlags->mAllFlags;
}
virtual TString GetTemplateFileName() virtual TString GetTemplateFileName()
{ {
ASSERT(IsArchetype() || mpArchetype); ASSERT(IsArchetype() || mpArchetype);

View File

@ -18,7 +18,7 @@ public:
Arc.SerializePrimitive( (float&) ValueRef(pData) ); Arc.SerializePrimitive( (float&) ValueRef(pData) );
} }
virtual TString ValueAsString(void* pData) virtual TString ValueAsString(void* pData) const
{ {
return TString::FromFloat( Value(pData) ); return TString::FromFloat( Value(pData) );
} }

View File

@ -18,7 +18,7 @@ public:
Arc.SerializePrimitive( (u32&) ValueRef(pData) ); Arc.SerializePrimitive( (u32&) ValueRef(pData) );
} }
virtual TString ValueAsString(void* pData) virtual TString ValueAsString(void* pData) const
{ {
return TString::FromInt32( Value(pData), 0, 10 ); return TString::FromInt32( Value(pData), 0, 10 );
} }

View File

@ -26,7 +26,7 @@ public:
if (!mChildren.empty()) if (!mChildren.empty())
{ {
IPropertyNew* pLastChild = mChildren.back(); IPropertyNew* pLastChild = mChildren.back();
return _GetOffset() + pLastChild->DataSize(); return (pLastChild->Offset() - Offset()) + pLastChild->DataSize();
} }
else else
{ {
@ -36,7 +36,11 @@ public:
virtual u32 DataAlignment() const virtual u32 DataAlignment() const
{ {
return (mChildren.empty() ? 1 : mChildren[0]->DataAlignment()); // TODO. Should be aligned with the first child, but this function is called before children are loaded.
// So for now just use 8 to ensure correct alignment for all child types, but this is wasteful...
return 8;
//return (mChildren.empty() ? 1 : mChildren[0]->DataAlignment());
} }
virtual void Construct(void* pData) const virtual void Construct(void* pData) const

View File

@ -50,7 +50,7 @@ public:
/** Accessors */ /** Accessors */
inline CScriptObject* Object() const { return mpObject; } inline CScriptObject* Object() const { return mpObject; }
inline PropertyClass* Property() const { return mpProperty; } inline PropertyClass* Property() const { return mpProperty; }
inline ValueType Get() const { ASSERT(IsValid()); return *((ValueType*) mpProperty->RawValuePtr( mpObject->PropertyData() )); } inline ValueType Get() const { return IsValid() ? *((ValueType*) mpProperty->RawValuePtr( mpObject->PropertyData() )) : ValueType(); }
inline void Set(const ValueType& kIn) const { if (IsValid()) *((ValueType*) mpProperty->RawValuePtr( mpObject->PropertyData() )) = kIn; } inline void Set(const ValueType& kIn) const { if (IsValid()) *((ValueType*) mpProperty->RawValuePtr( mpObject->PropertyData() )) = kIn; }
inline bool IsValid() const { return mpObject != nullptr && mpProperty != nullptr; } inline bool IsValid() const { return mpObject != nullptr && mpProperty != nullptr; }

View File

@ -496,13 +496,13 @@ void CScriptNode::PropertyModified(IPropertyNew* pProp)
if (pProp == pTemplate->NameProperty()) if (pProp == pTemplate->NameProperty())
SetName("[" + mpInstance->Template()->Name() + "] " + mpInstance->InstanceName()); SetName("[" + mpInstance->Template()->Name() + "] " + mpInstance->InstanceName());
else if (pProp == pTemplate->PositionProperty()) else if (pProp == pTemplate->PositionProperty() || pProp->Parent() == pTemplate->PositionProperty())
mPosition = mpInstance->Position(); mPosition = mpInstance->Position();
else if (pProp == pTemplate->RotationProperty()) else if (pProp == pTemplate->RotationProperty() || pProp->Parent() == pTemplate->RotationProperty())
mRotation = CQuaternion::FromEuler(mpInstance->Rotation()); mRotation = CQuaternion::FromEuler(mpInstance->Rotation());
else if (pProp == pTemplate->ScaleProperty()) else if (pProp == pTemplate->ScaleProperty() || pProp->Parent() == pTemplate->ScaleProperty())
mScale = mpInstance->Scale(); mScale = mpInstance->Scale();
MarkTransformChanged(); MarkTransformChanged();
@ -560,7 +560,7 @@ void CScriptNode::GeneratePosition()
if (!mHasValidPosition) if (!mHasValidPosition)
{ {
// Default to center of the active area; this is to prevent recursion issues // Default to center of the active area; this is to prevent recursion issues
CTransform4f& AreaTransform = mpScene->ActiveArea()->Transform(); CTransform4f AreaTransform = mpScene->ActiveArea()->Transform();
mPosition = CVector3f(AreaTransform[0][3], AreaTransform[1][3], AreaTransform[2][3]); mPosition = CVector3f(AreaTransform[0][3], AreaTransform[1][3], AreaTransform[2][3]);
mHasValidPosition = true; mHasValidPosition = true;
MarkTransformChanged(); MarkTransformChanged();

View File

@ -764,9 +764,10 @@ void CModelEditorWindow::ConvertToDDS()
if (Input.isEmpty()) return; if (Input.isEmpty()) return;
TString TexFilename = TO_TSTRING(Input); TString TexFilename = TO_TSTRING(Input);
CTexture *pTex = CTextureDecoder::LoadDDS( CFileInStream(TexFilename, IOUtil::eLittleEndian), nullptr ); CFileInStream InTextureFile(TexFilename, IOUtil::eLittleEndian);
TString OutName = TexFilename.GetFilePathWithoutExtension() + ".dds"; CTexture *pTex = CTextureDecoder::LoadTXTR( InTextureFile, nullptr );
TString OutName = TexFilename.GetFilePathWithoutExtension() + ".dds";
CFileOutStream Out(OutName, IOUtil::eLittleEndian); CFileOutStream Out(OutName, IOUtil::eLittleEndian);
if (!Out.IsValid()) QMessageBox::warning(this, "Error", "Couldn't open output DDS!"); if (!Out.IsValid()) QMessageBox::warning(this, "Error", "Couldn't open output DDS!");
@ -786,7 +787,8 @@ void CModelEditorWindow::ConvertToTXTR()
if (Input.isEmpty()) return; if (Input.isEmpty()) return;
TString TexFilename = TO_TSTRING(Input); TString TexFilename = TO_TSTRING(Input);
CTexture *pTex = CTextureDecoder::LoadDDS(CFileInStream(TexFilename, IOUtil::eLittleEndian), nullptr); CFileInStream InTextureFile = CFileInStream(TexFilename, IOUtil::eLittleEndian);
CTexture *pTex = CTextureDecoder::LoadDDS(InTextureFile, nullptr);
TString OutName = TexFilename.GetFilePathWithoutExtension() + ".txtr"; TString OutName = TexFilename.GetFilePathWithoutExtension() + ".txtr";
if ((pTex->TexelFormat() != eDXT1) || (pTex->NumMipMaps() > 1)) if ((pTex->TexelFormat() != eDXT1) || (pTex->NumMipMaps() > 1))

View File

@ -354,97 +354,134 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
if (!mpModel) return; if (!mpModel) return;
if (!pEditor) return; if (!pEditor) return;
//FIXME IEditPropertyCommand* pCommand = nullptr;
/* IPropertyNew *pProp = mpModel->PropertyForIndex(rkIndex, false); IPropertyNew *pProp = mpModel->PropertyForIndex(rkIndex, true);
bool HadEditInProgress = mEditInProgress; void* pData = mpModel->GetPropertyData();
mEditInProgress = mInRelayWidgetEdit && (pEditor->hasFocus() || pProp->Type() == EPropertyTypeNew::Color);
bool EditJustFinished = (!mEditInProgress && HadEditInProgress);
bool Matches = false;
IUndoCommand* pCommand = nullptr;
if (pProp) if (pProp)
{ {
switch (pProp->Type()) EPropertyTypeNew Type = pProp->Type();
{
case EPropertyTypeNew::Bool: if (Type != EPropertyTypeNew::Array)
{ {
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor); // TODO: support this for non script object properties
bool NewValue = pCommand = new CEditScriptPropertyCommand(mpEditor, mpModel->GetScriptObject(), pProp);
pCommand = new TEditScriptPropertyCommand<CBoolProperty>(pProp, mpModel->GetScriptObject(), mpEditor, pCheckBox->isChecked(), pCommand->SaveOldData();
bool NewValue = TEditScriptPropertyCommand<CBoolProperty>(pProp,
TBoolProperty *pBool = static_cast<TBoolProperty*>(pProp); // Handle sub-properties of flags and animation sets
pBool->Set(pCheckBox->isChecked()); if (rkIndex.internalId() & 0x80000000)
break; {
if (pProp->Type() == EPropertyTypeNew::AnimationSet)
SetCharacterModelData(pEditor, rkIndex);
else if (pProp->Type() == EPropertyTypeNew::Flags)
{
QCheckBox* pCheckBox = static_cast<QCheckBox*>(pEditor);
CFlagsProperty* pFlags = static_cast<CFlagsProperty*>(pProp);
u32 Mask = pFlags->FlagMask(rkIndex.row());
int Flags = pFlags->Value(pData);
if (pCheckBox->isChecked()) Flags |= Mask;
else Flags &= ~Mask;
pFlags->ValueRef(pData) = Flags;
}
}
else
{
switch (pProp->Type())
{
case EPropertyTypeNew::Bool:
{
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor);
CBoolProperty* pBool = static_cast<CBoolProperty*>(pProp);
pBool->ValueRef(pData) = pCheckBox->isChecked();
break;
}
case EPropertyTypeNew::Short:
{
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
CShortProperty* pShort = static_cast<CShortProperty*>(pProp);
pShort->ValueRef(pData) = pSpinBox->value();
break;
}
case EPropertyTypeNew::Int:
{
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
CIntProperty* pInt = static_cast<CIntProperty*>(pProp);
pInt->ValueRef(pData) = pSpinBox->value();
break;
}
case EPropertyTypeNew::Sound:
{
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
CSoundProperty* pSound = static_cast<CSoundProperty*>(pProp);
pSound->ValueRef(pData) = pSpinBox->value();
break;
}
case EPropertyTypeNew::Float:
{
WDraggableSpinBox* pSpinBox = static_cast<WDraggableSpinBox*>(pEditor);
CFloatProperty* pFloat = static_cast<CFloatProperty*>(pProp);
pFloat->ValueRef(pData) = (float) pSpinBox->value();
break;
}
case EPropertyTypeNew::Color:
{
WColorPicker* pColorPicker = static_cast<WColorPicker*>(pEditor);
CColorProperty* pColor = static_cast<CColorProperty*>(pProp);
QColor Color = pColorPicker->Color();
pColor->ValueRef(pData) = TO_CCOLOR(Color);
break;
}
case EPropertyTypeNew::String:
{
QLineEdit* pLineEdit = static_cast<QLineEdit*>(pEditor);
CStringProperty* pString = static_cast<CStringProperty*>(pProp);
pString->ValueRef(pData) = TO_TSTRING(pLineEdit->text());
break;
}
case EPropertyTypeNew::Enum:
case EPropertyTypeNew::Choice:
{
QComboBox* pComboBox = static_cast<QComboBox*>(pEditor);
CEnumProperty* pEnum = static_cast<CEnumProperty*>(pProp);
pEnum->ValueRef(pData) = pEnum->ValueID(pComboBox->currentIndex());
break;
}
case EPropertyTypeNew::Asset:
{
CResourceSelector* pSelector = static_cast<CResourceSelector*>(pEditor);
CResourceEntry* pEntry = pSelector->Entry();
CAssetProperty* pAsset = static_cast<CAssetProperty*>(pProp);
pAsset->ValueRef(pData) = (pEntry ? pEntry->ID() : CAssetID::InvalidID(pAsset->Game()));
break;
}
}
}
pCommand->SaveNewData();
} }
case eShortProperty: // Array
else
{ {
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor); //FIXME
TShortProperty *pShort = static_cast<TShortProperty*>(pProp); /*
pShort->Set(pSpinBox->value()); WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
break; CArrayProperty* pArray = static_cast<CArrayProperty*>(pProp);
}
case eLongProperty:
case eSoundProperty:
{
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
TLongProperty *pLong = static_cast<TLongProperty*>(pProp);
pLong->Set(pSpinBox->value());
break;
}
case eFloatProperty:
{
WDraggableSpinBox *pSpinBox = static_cast<WDraggableSpinBox*>(pEditor);
TFloatProperty *pFloat = static_cast<TFloatProperty*>(pProp);
pFloat->Set((float) pSpinBox->value());
break;
}
case eColorProperty:
{
WColorPicker *pColorPicker = static_cast<WColorPicker*>(pEditor);
TColorProperty *pColor = static_cast<TColorProperty*>(pProp);
QColor Color = pColorPicker->Color();
pColor->Set(TO_CCOLOR(Color));
break;
}
case eStringProperty:
{
QLineEdit *pLineEdit = static_cast<QLineEdit*>(pEditor);
TStringProperty *pString = static_cast<TStringProperty*>(pProp);
pString->Set(TO_TSTRING(pLineEdit->text()));
break;
}
case eEnumProperty:
{
QComboBox *pComboBox = static_cast<QComboBox*>(pEditor);
TEnumProperty *pEnum = static_cast<TEnumProperty*>(pProp);
CEnumTemplate *pTemp = static_cast<CEnumTemplate*>(pProp->Template());
pEnum->Set(pTemp->EnumeratorID(pComboBox->currentIndex()));
break;
}
case eAssetProperty:
{
CResourceSelector *pSelector = static_cast<CResourceSelector*>(pEditor);
CResourceEntry *pEntry = pSelector->Entry();
TAssetProperty *pAsset = static_cast<TAssetProperty*>(pProp);
pAsset->Set(pEntry ? pEntry->ID() : CAssetID::InvalidID(mpEditor->CurrentGame()));
break;
}
case eArrayProperty:
{
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
int NewCount = pSpinBox->value(); int NewCount = pSpinBox->value();
if (pArray->Count() != NewCount) if (pArray->Count() != NewCount)
@ -452,91 +489,35 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
CResizeScriptArrayCommand *pCmd = new CResizeScriptArrayCommand(pProp, mpEditor, mpModel, NewCount); CResizeScriptArrayCommand *pCmd = new CResizeScriptArrayCommand(pProp, mpEditor, mpModel, NewCount);
mpEditor->UndoStack()->push(pCmd); mpEditor->UndoStack()->push(pCmd);
} }
break; */
}
} }
} }
// Check for character/bitfield/vector/color sub-properties if (pCommand)
else if (rkIndex.internalId() & 0x1)
{
pProp = mpModel->PropertyForIndex(rkIndex, true);
IPropertyValue *pRawValue = pProp->RawValue();
pOldValue = pRawValue ? pRawValue->Clone() : nullptr;
if (pProp->Type() == eCharacterProperty)
SetCharacterModelData(pEditor, rkIndex);
else if (pProp->Type() == eBitfieldProperty)
{
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor);
TBitfieldProperty *pBitfield = static_cast<TBitfieldProperty*>(pProp);
u32 Mask = static_cast<CBitfieldTemplate*>(pProp->Template())->FlagMask(rkIndex.row());
int Flags = pBitfield->Get();
if (pCheckBox->isChecked()) Flags |= Mask;
else Flags &= ~Mask;
pBitfield->Set(Flags);
}
else
{
WDraggableSpinBox *pSpinBox = static_cast<WDraggableSpinBox*>(pEditor);
if (pProp->Type() == eVector3Property)
{
TVector3Property *pVector = static_cast<TVector3Property*>(pProp);
CVector3f Value = pVector->Get();
if (rkIndex.row() == 0) Value.X = (float) pSpinBox->value();
if (rkIndex.row() == 1) Value.Y = (float) pSpinBox->value();
if (rkIndex.row() == 2) Value.Z = (float) pSpinBox->value();
pVector->Set(Value);
}
else if (pProp->Type() == eColorProperty)
{
TColorProperty *pColor = static_cast<TColorProperty*>(pProp);
CColor Value = pColor->Get();
if (rkIndex.row() == 0) Value.R = (float) pSpinBox->value();
if (rkIndex.row() == 1) Value.G = (float) pSpinBox->value();
if (rkIndex.row() == 2) Value.B = (float) pSpinBox->value();
if (rkIndex.row() == 3) Value.A = (float) pSpinBox->value();
pColor->Set(Value);
}
}
}
if (pProp && pOldValue)
{ {
// Check for edit in progress // Check for edit in progress
bool Matches = pOldValue->Matches(pProp->RawValue()); bool DataChanged = pCommand->IsNewDataDifferent();
if (!Matches && mInRelayWidgetEdit && (pEditor->hasFocus() || pProp->Type() == eColorProperty)) if (DataChanged && mInRelayWidgetEdit && (pEditor->hasFocus() || pProp->Type() == EPropertyTypeNew::Color))
mEditInProgress = true; mEditInProgress = true;
bool EditInProgress = mEditInProgress; bool EditWasInProgress = mEditInProgress;
// Check for edit finished // Check for edit finished
if (!mInRelayWidgetEdit || (!pEditor->hasFocus() && pProp->Type() != eColorProperty)) if (!mInRelayWidgetEdit || (!pEditor->hasFocus() && pProp->Type() != EPropertyTypeNew::Color))
mEditInProgress = false; mEditInProgress = false;
// Create undo command // Push undo command
if (!Matches || EditInProgress) if (DataChanged || EditWasInProgress)
{ {
// Always consider the edit done for bool properties // Always consider the edit done for bool properties
CEditScriptPropertyCommand *pCommand = new CEditScriptPropertyCommand(pProp, mpEditor, pOldValue, (!mEditInProgress || pProp->Type() == eBoolProperty)); pCommand->SetEditComplete(!mEditInProgress || pProp->Type() == EPropertyTypeNew::Bool);
mpEditor->UndoStack()->push(pCommand); mpEditor->UndoStack()->push(pCommand);
} }
else else
delete pOldValue; delete pCommand;
}*/ }
} }
bool CPropertyDelegate::eventFilter(QObject *pObject, QEvent *pEvent) bool CPropertyDelegate::eventFilter(QObject *pObject, QEvent *pEvent)
@ -558,18 +539,16 @@ bool CPropertyDelegate::eventFilter(QObject *pObject, QEvent *pEvent)
// Character properties have separate functions because they're somewhat complicated - they have different layouts in different games // Character properties have separate functions because they're somewhat complicated - they have different layouts in different games
QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModelIndex& rkIndex) const QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModelIndex& rkIndex) const
{ {
//FIXME CAnimationSetProperty* pAnimSetProp = TPropCast<CAnimationSetProperty>(mpModel->PropertyForIndex(rkIndex, true));
/* TCharacterProperty *pProp = static_cast<TCharacterProperty*>(mpModel->PropertyForIndex(rkIndex, true)); CAnimationParameters Params = pAnimSetProp->Value(mpModel->GetPropertyData());
CAnimationParameters Params = pProp->Get();
// Determine property type // Determine property type
EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex); EPropertyTypeNew Type = DetermineCharacterPropType(Params.Version(), rkIndex);
if (Type == eUnknownProperty) return nullptr;
// Create widget // Create widget
if (Type == eAssetProperty) if (Type == EPropertyTypeNew::Asset)
{ {
CResourceSelector *pSelector = new CResourceSelector(pParent); CResourceSelector* pSelector = new CResourceSelector(pParent);
pSelector->SetFrameVisible(false); pSelector->SetFrameVisible(false);
if (Params.Version() <= eEchoes) if (Params.Version() <= eEchoes)
@ -581,94 +560,87 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
return pSelector; return pSelector;
} }
if (Type == eEnumProperty) else if (Type == EPropertyTypeNew::Enum || Type == EPropertyTypeNew::Choice)
{ {
QComboBox *pComboBox = new QComboBox(pParent); QComboBox* pComboBox = new QComboBox(pParent);
CAnimSet* pAnimSet = Params.AnimSet();
CAnimSet *pAnimSet = Params.AnimSet();
if (pAnimSet) if (pAnimSet)
{ {
for (u32 iChr = 0; iChr < pAnimSet->NumCharacters(); iChr++) for (u32 CharIdx = 0; CharIdx < pAnimSet->NumCharacters(); CharIdx++)
pComboBox->addItem(TO_QSTRING(pAnimSet->Character(iChr)->Name)); pComboBox->addItem(TO_QSTRING(pAnimSet->Character(CharIdx)->Name));
} }
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int)); CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int));
return pComboBox; return pComboBox;
} }
if (Type == eLongProperty) else if (Type == EPropertyTypeNew::Int)
{ {
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)); CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int));
return pSpinBox; return pSpinBox;
}*/ }
return nullptr; return nullptr;
} }
void CPropertyDelegate::SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const void CPropertyDelegate::SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const
{ {
//FIXME CAnimationSetProperty* pAnimSetProp = TPropCast<CAnimationSetProperty>(mpModel->PropertyForIndex(rkIndex, true));
/* CAnimationParameters Params = pAnimSetProp->Value(mpModel->GetPropertyData());
TCharacterProperty *pProp = static_cast<TCharacterProperty*>(mpModel->PropertyForIndex(rkIndex, true)); EPropertyTypeNew Type = DetermineCharacterPropType(Params.Version(), rkIndex);
CAnimationParameters Params = pProp->Get();
EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex);
if (Type == eAssetProperty) if (Type == EPropertyTypeNew::Asset)
{ {
static_cast<CResourceSelector*>(pEditor)->SetResource(Params.AnimSet()); static_cast<CResourceSelector*>(pEditor)->SetResource(Params.AnimSet());
} }
else if (Type == eEnumProperty) else if (Type == EPropertyTypeNew::Enum || Type == EPropertyTypeNew::Choice)
{ {
static_cast<QComboBox*>(pEditor)->setCurrentIndex(Params.CharacterIndex()); static_cast<QComboBox*>(pEditor)->setCurrentIndex(Params.CharacterIndex());
} }
else if (Type == eLongProperty && !pEditor->hasFocus()) else if (Type == EPropertyTypeNew::Int && !pEditor->hasFocus())
{ {
int UnkIndex = (Params.Version() <= eEchoes ? rkIndex.row() - 2 : rkIndex.row() - 1); int UnkIndex = (Params.Version() <= eEchoes ? rkIndex.row() - 2 : rkIndex.row() - 1);
u32 Value = Params.Unknown(UnkIndex); u32 Value = Params.Unknown(UnkIndex);
static_cast<WIntegralSpinBox*>(pEditor)->setValue(Value); static_cast<WIntegralSpinBox*>(pEditor)->setValue(Value);
} }
*/
} }
void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelIndex& rkIndex) const void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelIndex& rkIndex) const
{ {
//FIXME CAnimationSetProperty* pAnimSetProp = TPropCast<CAnimationSetProperty>(mpModel->PropertyForIndex(rkIndex, true));
/* CAnimationParameters Params = pAnimSetProp->Value(mpModel->GetPropertyData());
CAnimationSetProperty* pAnimSet = TPropCast<CAnimationSetProperty>(mpModel->PropertyForIndex(rkIndex, true)); EPropertyTypeNew Type = DetermineCharacterPropType(Params.Version(), rkIndex);
CAnimationParameters Params = pAnimSet->Get();
EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex);
if (Type == eAssetProperty) if (Type == EPropertyTypeNew::Asset)
{ {
CResourceEntry *pEntry = static_cast<CResourceSelector*>(pEditor)->Entry(); CResourceEntry *pEntry = static_cast<CResourceSelector*>(pEditor)->Entry();
Params.SetResource( pEntry ? pEntry->ID() : CAssetID::InvalidID(mpEditor->CurrentGame()) ); Params.SetResource( pEntry ? pEntry->ID() : CAssetID::InvalidID(mpEditor->CurrentGame()) );
} }
else if (Type == eEnumProperty) else if (Type == EPropertyTypeNew::Enum || Type == EPropertyTypeNew::Choice)
{ {
Params.SetCharIndex( static_cast<QComboBox*>(pEditor)->currentIndex() ); Params.SetCharIndex( static_cast<QComboBox*>(pEditor)->currentIndex() );
} }
else if (Type == eLongProperty) else if (Type == EPropertyTypeNew::Int)
{ {
int UnkIndex = (Params.Version() <= eEchoes ? rkIndex.row() - 2 : rkIndex.row() - 1); int UnkIndex = (Params.Version() <= eEchoes ? rkIndex.row() - 2 : rkIndex.row() - 1);
Params.SetUnknown(UnkIndex, static_cast<WIntegralSpinBox*>(pEditor)->value() ); Params.SetUnknown(UnkIndex, static_cast<WIntegralSpinBox*>(pEditor)->value() );
} }
pProp->Set(Params); pAnimSetProp->ValueRef(mpModel->GetPropertyData()) = Params;
// If we just updated the resource, make sure all the sub-properties of the character are flagged as changed. // If we just updated the resource, make sure all the sub-properties of the character are flagged as changed.
// We want to do this -after- updating the anim params on the property, which is why we have a second type check. // We want to do this -after- updating the anim params on the property, which is why we have a second type check.
if (Type == eAssetProperty) if (Type == EPropertyTypeNew::Asset)
{ {
QModelIndex ParentIndex = rkIndex.parent(); QModelIndex ParentIndex = rkIndex.parent();
mpModel->dataChanged(mpModel->index(1, 1, ParentIndex), mpModel->index(mpModel->rowCount(ParentIndex) - 1, 1, ParentIndex)); mpModel->dataChanged(mpModel->index(1, 1, ParentIndex), mpModel->index(mpModel->rowCount(ParentIndex) - 1, 1, ParentIndex));
} }
*/
} }
EPropertyTypeNew CPropertyDelegate::DetermineCharacterPropType(EGame Game, const QModelIndex& rkIndex) const EPropertyTypeNew CPropertyDelegate::DetermineCharacterPropType(EGame Game, const QModelIndex& rkIndex) const

View File

@ -18,14 +18,14 @@ CPropertyModel::CPropertyModel(QObject *pParent /*= 0*/)
int CPropertyModel::RecursiveBuildArrays(IPropertyNew* pProperty, int ParentID) int CPropertyModel::RecursiveBuildArrays(IPropertyNew* pProperty, int ParentID)
{ {
int MyID = mProperties.size();
mProperties << SProperty(); mProperties << SProperty();
SProperty& Property = mProperties.back();
Property.pProperty = pProperty;
Property.ParentID = ParentID;
int MyID = mProperties.size() - 1; mProperties[MyID].pProperty = pProperty;
mProperties[MyID].ParentID = ParentID;
int RowNumber = (ParentID >= 0 ? mProperties[ParentID].ChildIDs.size() : 0); int RowNumber = (ParentID >= 0 ? mProperties[ParentID].ChildIDs.size() : 0);
Property.Index = createIndex(RowNumber, 0, pProperty); mProperties[MyID].Index = createIndex(RowNumber, 0, MyID);
if (pProperty->Type() == EPropertyTypeNew::Array) if (pProperty->Type() == EPropertyTypeNew::Array)
{ {
@ -34,7 +34,7 @@ int CPropertyModel::RecursiveBuildArrays(IPropertyNew* pProperty, int ParentID)
for (u32 ElementIdx = 0; ElementIdx < pArray->ArrayCount(mpPropertyData); ElementIdx++) for (u32 ElementIdx = 0; ElementIdx < pArray->ArrayCount(mpPropertyData); ElementIdx++)
{ {
int NewChildID = RecursiveBuildArrays( pArray->Archetype(), MyID ); int NewChildID = RecursiveBuildArrays( pArray->Archetype(), MyID );
Property.ChildIDs.push_back(NewChildID); mProperties[MyID].ChildIDs.push_back(NewChildID);
} }
} }
else else
@ -42,7 +42,7 @@ int CPropertyModel::RecursiveBuildArrays(IPropertyNew* pProperty, int ParentID)
for (u32 ChildIdx = 0; ChildIdx < pProperty->NumChildren(); ChildIdx++) for (u32 ChildIdx = 0; ChildIdx < pProperty->NumChildren(); ChildIdx++)
{ {
int NewChildID = RecursiveBuildArrays( pProperty->ChildByIndex(ChildIdx), MyID ); int NewChildID = RecursiveBuildArrays( pProperty->ChildByIndex(ChildIdx), MyID );
Property.ChildIDs.push_back(NewChildID); mProperties[MyID].ChildIDs.push_back(NewChildID);
} }
} }
@ -74,7 +74,7 @@ void CPropertyModel::ConfigureIntrinsic(CGameProject* pProject, IPropertyNew* pR
void CPropertyModel::ConfigureScript(CGameProject* pProject, IPropertyNew* pRootProperty, CScriptObject* pObject) void CPropertyModel::ConfigureScript(CGameProject* pProject, IPropertyNew* pRootProperty, CScriptObject* pObject)
{ {
ConfigureIntrinsic(pProject, pRootProperty, pObject); ConfigureIntrinsic(pProject, pRootProperty, pObject ? pObject->PropertyData() : nullptr);
mpObject = pObject; mpObject = pObject;
} }
@ -166,7 +166,7 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
if (Role == Qt::DisplayRole || (Role == Qt::ToolTipRole && rkIndex.column() == 1) ) if (Role == Qt::DisplayRole || (Role == Qt::ToolTipRole && rkIndex.column() == 1) )
{ {
if (rkIndex.internalId() & 0x1) if (rkIndex.internalId() & 0x80000000)
{ {
IPropertyNew *pProp = PropertyForIndex(rkIndex, true); IPropertyNew *pProp = PropertyForIndex(rkIndex, true);
EPropertyTypeNew Type = pProp->Type(); EPropertyTypeNew Type = pProp->Type();
@ -321,11 +321,6 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
// No display text on properties with persistent editors // No display text on properties with persistent editors
case EPropertyTypeNew::Bool: case EPropertyTypeNew::Bool:
if (Role == Qt::DisplayRole)
return TPropCast<CBoolProperty>(pProp)->Value(mpPropertyData) ? "True" : "False";
else
return "";
case EPropertyTypeNew::Asset: case EPropertyTypeNew::Asset:
case EPropertyTypeNew::Color: case EPropertyTypeNew::Color:
if (Role == Qt::DisplayRole) if (Role == Qt::DisplayRole)
@ -341,12 +336,12 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
if (Role == Qt::ToolTipRole && rkIndex.column() == 0) if (Role == Qt::ToolTipRole && rkIndex.column() == 0)
{ {
if (!(rkIndex.internalId() & 0x1)) if (!(rkIndex.internalId() & 0x80000000))
{ {
// Add name // Add name
IPropertyNew *pProp = PropertyForIndex(rkIndex, false); IPropertyNew *pProp = PropertyForIndex(rkIndex, false);
QString DisplayText = data(rkIndex, Qt::DisplayRole).toString(); QString DisplayText = data(rkIndex, Qt::DisplayRole).toString();
QString Text = QString("<b>%1</b> <i>(%2)</i>").arg(DisplayText).arg(TO_QSTRING(PropEnumToPropString(pProp->Type()))); QString Text = QString("<b>%1</b> <i>(%2)</i>").arg(DisplayText).arg(pProp->HashableTypeName());
// Add uncooked notification // Add uncooked notification
if (pProp->CookPreference() == ECookPreferenceNew::Never) if (pProp->CookPreference() == ECookPreferenceNew::Never)
@ -444,7 +439,10 @@ QModelIndex CPropertyModel::parent(const QModelIndex& rkChild) const
else else
ID = mProperties[ID].ParentID; ID = mProperties[ID].ParentID;
return mProperties[ID].Index; if (ID >= 0)
return mProperties[ID].Index;
else
return QModelIndex();
} }
Qt::ItemFlags CPropertyModel::flags(const QModelIndex& rkIndex) const Qt::ItemFlags CPropertyModel::flags(const QModelIndex& rkIndex) const

View File

@ -81,7 +81,7 @@ void CPropertyView::SetEditor(CWorldEditor *pEditor)
{ {
mpEditor = pEditor; mpEditor = pEditor;
mpDelegate->SetEditor(pEditor); mpDelegate->SetEditor(pEditor);
connect(mpEditor, SIGNAL(PropertyModified(CScriptObject*,IProperty*)), mpModel, SLOT(NotifyPropertyModified(CScriptObject*,IProperty*))); connect(mpEditor, SIGNAL(PropertyModified(CScriptObject*,IPropertyNew*)), mpModel, SLOT(NotifyPropertyModified(CScriptObject*,IPropertyNew*)));
} }
void CPropertyView::SetInstance(CScriptObject *pObj) void CPropertyView::SetInstance(CScriptObject *pObj)

View File

@ -63,6 +63,7 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent)
mpProxyModel = new CResourceProxyModel(this); mpProxyModel = new CResourceProxyModel(this);
mpProxyModel->setSourceModel(mpModel); mpProxyModel->setSourceModel(mpModel);
mpUI->ResourceTableView->setModel(mpProxyModel); mpUI->ResourceTableView->setModel(mpProxyModel);
mpUI->ResourceTableView->resizeRowsToContents();
QHeaderView *pHeader = mpUI->ResourceTableView->horizontalHeader(); QHeaderView *pHeader = mpUI->ResourceTableView->horizontalHeader();
pHeader->setSectionResizeMode(0, QHeaderView::Stretch); pHeader->setSectionResizeMode(0, QHeaderView::Stretch);
@ -158,6 +159,7 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent)
connect(mpUI->ResourceTableView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnResourceSelectionChanged(QModelIndex))); connect(mpUI->ResourceTableView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnResourceSelectionChanged(QModelIndex)));
connect(mpProxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), mpUI->ResourceTableView, SLOT(resizeRowsToContents())); connect(mpProxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), mpUI->ResourceTableView, SLOT(resizeRowsToContents()));
connect(mpProxyModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), mpUI->ResourceTableView, SLOT(resizeRowsToContents())); connect(mpProxyModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), mpUI->ResourceTableView, SLOT(resizeRowsToContents()));
connect(mpProxyModel, SIGNAL(modelReset()), mpUI->ResourceTableView, SLOT(resizeRowsToContents()));
connect(mpFilterAllBox, SIGNAL(toggled(bool)), this, SLOT(OnFilterTypeBoxTicked(bool))); connect(mpFilterAllBox, SIGNAL(toggled(bool)), this, SLOT(OnFilterTypeBoxTicked(bool)));
connect(gpEdApp, SIGNAL(ActiveProjectChanged(CGameProject*)), this, SLOT(UpdateStore())); connect(gpEdApp, SIGNAL(ActiveProjectChanged(CGameProject*)), this, SLOT(UpdateStore()));
} }
@ -874,6 +876,9 @@ void CResourceBrowser::UpdateFilter()
UpdateDescriptionLabel(); UpdateDescriptionLabel();
mpProxyModel->SetSearchString( TO_TSTRING(mpUI->SearchBar->text()) ); mpProxyModel->SetSearchString( TO_TSTRING(mpUI->SearchBar->text()) );
mpProxyModel->invalidate(); mpProxyModel->invalidate();
// not sure why I need to do this here? but the resize mode seems to get reset otherwise
mpUI->ResourceTableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
} }
void CResourceBrowser::UpdateUndoActionStates() void CResourceBrowser::UpdateUndoActionStates()

View File

@ -7,29 +7,83 @@
#include "Editor/PropertyEdit/CPropertyModel.h" #include "Editor/PropertyEdit/CPropertyModel.h"
#include "Editor/WorldEditor/CWorldEditor.h" #include "Editor/WorldEditor/CWorldEditor.h"
template<class PropertyClass> class IEditPropertyCommand : public IUndoCommand
class TEditScriptPropertyCommand : public IUndoCommand
{ {
typedef typename PropertyClass::ValueType ValueType; std::vector<char> mOldData;
std::vector<char> mNewData;
CWorldEditor *mpEditor; protected:
CInstancePtr mpInstance; IPropertyNew* mpProperty;
PropertyClass* mpProperty;
ValueType mOldValue;
ValueType mNewValue;
bool mCommandEnded; 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: public:
TEditScriptPropertyCommand(PropertyClass* pProp, CScriptObject* pInstance, CWorldEditor* pEditor, ValueType NewValue, bool IsDone, const QString& rkCommandName = "Edit Property") IEditPropertyCommand(IPropertyNew* pProperty, const QString& rkCommandName = "Edit Property")
: IUndoCommand(rkCommandName) : IUndoCommand(rkCommandName)
, mpEditor(pEditor) , mpProperty(pProperty)
, mpInstance(pInstance) , mSavedOldData(false)
, mpProperty(pProp) , mSavedNewData(false)
, mOldValue(pProp->Value(pInstance->PropertyData()))
, mNewValue(NewValue)
, mCommandEnded(IsDone)
{} {}
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 int id() const
{ {
return eEditScriptPropertyCmd; return eEditScriptPropertyCmd;
@ -39,13 +93,29 @@ public:
{ {
if (!mCommandEnded) if (!mCommandEnded)
{ {
TEditScriptPropertyCommand* pkCmd = dynamic_cast<TEditScriptPropertyCommand>(pkOther); const IEditPropertyCommand* pkCmd = dynamic_cast<const IEditPropertyCommand*>(pkOther);
if (pkCmd && pkCmd->mpProperty == mpProperty && pkCmd->mpInstance == mpInstance) if (pkCmd && pkCmd->mpProperty == mpProperty)
{ {
mNewValue = pkCmd->mNewValue; std::vector<void*> MyPointers;
mCommandEnded = pkCmd->mCommandEnded; GetObjectDataPointers(MyPointers);
return true;
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;
}
} }
} }
@ -54,17 +124,15 @@ public:
void undo() void undo()
{ {
void* pData = mpInstance->PropertyData(); ASSERT(mSavedOldData && mSavedNewData);
mpProperty->ValueRef(pData) = mOldValue; RestoreObjectStateFromArray(mOldData);
mpEditor->OnPropertyModified(mpProperty);
mCommandEnded = true; mCommandEnded = true;
} }
void redo() void redo()
{ {
void* pData = mpInstance->PropertyData(); ASSERT(mSavedOldData && mSavedNewData);
mpProperty->ValueRef(pData) = mNewValue; RestoreObjectStateFromArray(mNewData);
mpEditor->OnPropertyModified(mpProperty);
} }
bool AffectsCleanState() const bool AffectsCleanState() const
@ -73,22 +141,46 @@ public:
} }
}; };
/*class CEditScriptPropertyCommand : public IUndoCommand class CEditScriptPropertyCommand : public IEditPropertyCommand
{ {
CWorldEditor *mpEditor; std::vector<CInstancePtr> mInstances;
CPropertyPtr mpProp; CWorldEditor* mpEditor;
IPropertyValue *mpOldValue;
IPropertyValue *mpNewValue;
bool mCommandEnded;
public: public:
CEditScriptPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, IPropertyValue *pOldValue, bool IsDone, const QString& rkCommandName = "Edit Property"); CEditScriptPropertyCommand(CWorldEditor* pEditor, CScriptObject* pInstance, IPropertyNew* pProperty, const QString& rkCommandName = "Edit Property")
~CEditScriptPropertyCommand(); : IEditPropertyCommand(pProperty, rkCommandName)
int id() const; , mpEditor(pEditor)
bool mergeWith(const QUndoCommand *pkOther); {
void undo(); mInstances.push_back( CInstancePtr(pInstance) );
void redo(); }
bool AffectsCleanState() const { return true; }
};*/ 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();
}
}
virtual void undo() override
{
IEditPropertyCommand::undo();
NotifyWorldEditor();
}
virtual void redo() override
{
IEditPropertyCommand::redo();
NotifyWorldEditor();
}
void NotifyWorldEditor()
{
for (int InstanceIdx = 0; InstanceIdx < mInstances.size(); InstanceIdx++)
mpEditor->OnPropertyModified(*mInstances[InstanceIdx], mpProperty);
}
};
#endif // CEDITSCRIPTPROPERTYCOMMAND_H #endif // CEDITSCRIPTPROPERTYCOMMAND_H

View File

@ -34,8 +34,10 @@ protected slots:
if ( mpSoftValidator ) if ( mpSoftValidator )
{ {
QString Text = text();
int DummyPos; int DummyPos;
if ( mpSoftValidator->validate(text(), DummyPos) == QValidator::Acceptable )
if ( mpSoftValidator->validate(Text, DummyPos) == QValidator::Acceptable )
{ {
NewValidity = true; NewValidity = true;
setStyleSheet("border: 1px solid green"); setStyleSheet("border: 1px solid green");

View File

@ -569,11 +569,12 @@ void CWorldEditor::OnLinksModified(const QList<CScriptObject*>& rkInstances)
emit InstanceLinksModified(rkInstances); emit InstanceLinksModified(rkInstances);
} }
void CWorldEditor::OnPropertyModified(IPropertyNew *pProp) void CWorldEditor::OnPropertyModified(CScriptObject* pObject, IPropertyNew *pProp)
{ {
if (!mpSelection->IsEmpty() && mpSelection->Front()->NodeType() == eScriptNode) CScriptNode *pScript = mScene.NodeForInstance(pObject);
if (pScript)
{ {
CScriptNode *pScript = static_cast<CScriptNode*>(mpSelection->Front());
pScript->PropertyModified(pProp); pScript->PropertyModified(pProp);
// If this is an editor property, update other parts of the UI to reflect the new value. // If this is an editor property, update other parts of the UI to reflect the new value.
@ -581,23 +582,24 @@ void CWorldEditor::OnPropertyModified(IPropertyNew *pProp)
{ {
UpdateStatusBar(); UpdateStatusBar();
UpdateSelectionUI(); UpdateSelectionUI();
mpSelection->UpdateBounds();
} }
// If this is a model/character, then we'll treat this as a modified selection. This is to make sure the selection bounds updates.
if (pProp->Type() == EPropertyTypeNew::Asset)
{
CAssetProperty *pAsset = TPropCast<CAssetProperty>(pProp);
const CResTypeFilter& rkFilter = pAsset->GetTypeFilter();
if (rkFilter.Accepts(eModel) || rkFilter.Accepts(eAnimSet) || rkFilter.Accepts(eCharacter))
SelectionModified();
}
else if (pProp->Type() == EPropertyTypeNew::AnimationSet)
SelectionModified();
// Emit signal so other widgets can react to the property change
emit PropertyModified(pScript->Instance(), pProp);
} }
// If this is a model/character, then we'll treat this as a modified selection. This is to make sure the selection bounds updates.
if (pProp->Type() == EPropertyTypeNew::Asset)
{
CAssetProperty *pAsset = TPropCast<CAssetProperty>(pProp);
const CResTypeFilter& rkFilter = pAsset->GetTypeFilter();
if (rkFilter.Accepts(eModel) || rkFilter.Accepts(eAnimSet) || rkFilter.Accepts(eCharacter))
SelectionModified();
}
else if (pProp->Type() == EPropertyTypeNew::AnimationSet)
SelectionModified();
// Emit signal so other widgets can react to the property change
emit PropertyModified(pObject, pProp);
} }
void CWorldEditor::SetSelectionActive(bool Active) void CWorldEditor::SetSelectionActive(bool Active)

View File

@ -122,7 +122,7 @@ public slots:
void OnActiveProjectChanged(CGameProject *pProj); void OnActiveProjectChanged(CGameProject *pProj);
void OnLinksModified(const QList<CScriptObject*>& rkInstances); void OnLinksModified(const QList<CScriptObject*>& rkInstances);
void OnPropertyModified(IPropertyNew *pProp); void OnPropertyModified(CScriptObject* pObject, IPropertyNew *pProp);
void SetSelectionActive(bool Active); void SetSelectionActive(bool Active);
void SetSelectionInstanceNames(const QString& rkNewName, bool IsDone); void SetSelectionInstanceNames(const QString& rkNewName, bool IsDone);
void SetSelectionLayer(CScriptLayer *pLayer); void SetSelectionLayer(CScriptLayer *pLayer);

View File

@ -65,7 +65,7 @@ void WEditorProperties::SyncToEditor(CWorldEditor *pEditor)
connect(mpEditor, SIGNAL(SelectionModified()), this, SLOT(OnSelectionModified())); connect(mpEditor, SIGNAL(SelectionModified()), this, SLOT(OnSelectionModified()));
connect(mpEditor, SIGNAL(LayersModified()), this, SLOT(OnLayersModified())); connect(mpEditor, SIGNAL(LayersModified()), this, SLOT(OnLayersModified()));
connect(mpEditor, SIGNAL(InstancesLayerChanged(QList<CScriptNode*>)), this, SLOT(OnInstancesLayerChanged(QList<CScriptNode*>))); connect(mpEditor, SIGNAL(InstancesLayerChanged(QList<CScriptNode*>)), this, SLOT(OnInstancesLayerChanged(QList<CScriptNode*>)));
connect(mpEditor, SIGNAL(PropertyModified(CScriptObject*,IProperty*)), this, SLOT(OnPropertyModified(CScriptObject*,IProperty*))); connect(mpEditor, SIGNAL(PropertyModified(CScriptObject*,IPropertyNew*)), this, SLOT(OnPropertyModified(CScriptObject*,IPropertyNew*)));
OnLayersModified(); OnLayersModified();
} }

View File

@ -73,7 +73,7 @@ int main(int argc, char *argv[])
// Load templates // Load templates
CTemplateLoader::LoadGameList(); CTemplateLoader::LoadGameList();
CTemplateLoader::LoadAllGames(); //CTemplateLoader::LoadAllGames();
//CTemplateWriter::SaveAllTemplates(); //CTemplateWriter::SaveAllTemplates();
// Execute application // Execute application

View File

@ -139,16 +139,6 @@ float CMatrix4f::Determinant() const
} }
// ************ OPERATORS ************ // ************ OPERATORS ************
inline float* CMatrix4f::operator[](long Index)
{
return m[Index];
}
inline const float* CMatrix4f::operator[](long Index) const
{
return m[Index];
}
CVector3f CMatrix4f::operator*(const CVector3f& rkVec) const CVector3f CMatrix4f::operator*(const CVector3f& rkVec) const
{ {
// For vec3 multiplication, the vector w component is considered to be 1.0 // For vec3 multiplication, the vector w component is considered to be 1.0

View File

@ -42,4 +42,14 @@ public:
static const CMatrix4f skIdentity; static const CMatrix4f skIdentity;
}; };
inline float* CMatrix4f::operator[](long Index)
{
return m[Index];
}
inline const float* CMatrix4f::operator[](long Index) const
{
return m[Index];
}
#endif // CMATRIX4_H #endif // CMATRIX4_H

View File

@ -43,7 +43,7 @@ void CVector3f::Serialize(IArchive& rArc)
TString CVector3f::ToString() const TString CVector3f::ToString() const
{ {
return TString::Format("%f.1, %f.1, %f.1", X, Y, Z); return TString::Format("%.1f, %.1f, %.1f", X, Y, Z);
} }
// ************ SWIZZLE ************ // ************ SWIZZLE ************