Added support for bitfield properties
This commit is contained in:
parent
8470923e45
commit
b187da3925
|
@ -392,12 +392,35 @@ void CTemplateWriter::SaveEnumTemplate(CEnumTemplate *pTemp, const std::string&
|
|||
enumXML.LinkEndChild(pDecl);
|
||||
|
||||
XMLElement *pBase = enumXML.NewElement("enum");
|
||||
pBase->SetName("name", name.c_str());
|
||||
SaveEnumerators(&enumXML, pBase, pTemp);
|
||||
enumXML.LinkEndChild(pBase);
|
||||
|
||||
enumXML.SaveFile(outFile.c_str());
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveBitfieldTemplate(CBitfieldTemplate *pTemp, const std::string& dir)
|
||||
{
|
||||
// Create directory
|
||||
std::string outFile = dir + pTemp->mSourceFile;
|
||||
std::string outDir = StringUtil::GetFileDirectory(outFile);
|
||||
std::string name = StringUtil::GetFileName(pTemp->mSourceFile);
|
||||
boost::filesystem::create_directory(outDir);
|
||||
|
||||
// Create new document and write enumerators to it
|
||||
XMLDocument bitfieldXML;
|
||||
|
||||
XMLDeclaration *pDecl = bitfieldXML.NewDeclaration();
|
||||
bitfieldXML.LinkEndChild(pDecl);
|
||||
|
||||
XMLElement *pBase = bitfieldXML.NewElement("bitfield");
|
||||
pBase->SetName("name", name.c_str());
|
||||
SaveBitFlags(&bitfieldXML, pBase, pTemp);
|
||||
bitfieldXML.LinkEndChild(pBase);
|
||||
|
||||
bitfieldXML.SaveFile(outFile.c_str());
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveProperties(XMLDocument *pDoc, XMLElement *pParent, CStructTemplate *pTemp, CMasterTemplate *pMaster, const std::string& dir)
|
||||
{
|
||||
for (u32 iProp = 0; iProp < pTemp->Count(); iProp++)
|
||||
|
@ -467,6 +490,30 @@ void CTemplateWriter::SaveProperties(XMLDocument *pDoc, XMLElement *pParent, CSt
|
|||
|
||||
pParent->LinkEndChild(pElem);
|
||||
}
|
||||
else if (pProp->Type() == eBitfieldProperty)
|
||||
{
|
||||
CBitfieldTemplate *pBitfieldTemp = static_cast<CBitfieldTemplate*>(pProp);
|
||||
bool isExternal = (!pBitfieldTemp->mSourceFile.empty());
|
||||
|
||||
XMLElement *pElem = pDoc->NewElement("bitfield");
|
||||
pElem->SetAttribute("ID", strID.c_str());
|
||||
|
||||
if ((!pMaster->HasPropertyList()) || (pProp->PropertyID() == -1))
|
||||
pElem->SetAttribute("name", pProp->Name().c_str());
|
||||
|
||||
if (isExternal)
|
||||
{
|
||||
SaveBitfieldTemplate(pBitfieldTemp, dir);
|
||||
pElem->SetAttribute("template", pBitfieldTemp->mSourceFile.c_str());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
SaveBitFlags(pDoc, pElem, pBitfieldTemp);
|
||||
}
|
||||
|
||||
pParent->LinkEndChild(pElem);
|
||||
}
|
||||
else
|
||||
{
|
||||
XMLElement *pElem = pDoc->NewElement("property");
|
||||
|
@ -511,3 +558,14 @@ void CTemplateWriter::SaveEnumerators(XMLDocument *pDoc, XMLElement *pParent, CE
|
|||
pParent->LinkEndChild(pElem);
|
||||
}
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveBitFlags(tinyxml2::XMLDocument *pDoc, tinyxml2::XMLElement *pParent, CBitfieldTemplate *pTemp)
|
||||
{
|
||||
for (u32 iFlag = 0; iFlag < pTemp->NumFlags(); iFlag++)
|
||||
{
|
||||
XMLElement *pElem = pDoc->NewElement("bitflag");
|
||||
pElem->SetAttribute("mask", StringUtil::ToHexString(pTemp->FlagMask(iFlag), true, true, 8).c_str());
|
||||
pElem->SetAttribute("name", pTemp->FlagName(iFlag).c_str());
|
||||
pParent->LinkEndChild(pElem);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@ public:
|
|||
static void SaveScriptTemplate(CScriptTemplate *pTemp, const std::string& dir);
|
||||
static void SaveStructTemplate(CStructTemplate *pTemp, CMasterTemplate *pMaster, const std::string& dir);
|
||||
static void SaveEnumTemplate(CEnumTemplate *pTemp, const std::string& dir);
|
||||
static void SaveBitfieldTemplate(CBitfieldTemplate *pTemp, const std::string& dir);
|
||||
static void SaveProperties(tinyxml2::XMLDocument *pDoc, tinyxml2::XMLElement *pParent, CStructTemplate *pTemp, CMasterTemplate *pMaster, const std::string& dir);
|
||||
static void SaveEnumerators(tinyxml2::XMLDocument *pDoc, tinyxml2::XMLElement *pParent, CEnumTemplate *pTemp);
|
||||
// todo: save enum templates
|
||||
static void SaveBitFlags(tinyxml2::XMLDocument *pDoc, tinyxml2::XMLElement *pParent, CBitfieldTemplate *pTemp);
|
||||
};
|
||||
|
||||
#endif // CTEMPLATEWRITER_H
|
||||
|
|
|
@ -58,6 +58,21 @@ CPropertyStruct* CScriptLoader::LoadStructMP1(CInputStream& SCLY, CStructTemplat
|
|||
pProp = new CLongProperty(v);
|
||||
break;
|
||||
}
|
||||
case eBitfieldProperty: {
|
||||
long v = SCLY.ReadLong();
|
||||
pProp = new CBitfieldProperty(v);
|
||||
|
||||
// Validate
|
||||
u32 mask = 0;
|
||||
CBitfieldTemplate *pBitfieldTemp = static_cast<CBitfieldTemplate*>(pPropTmp);
|
||||
for (u32 iMask = 0; iMask < pBitfieldTemp->NumFlags(); iMask++)
|
||||
mask |= pBitfieldTemp->FlagMask(iMask);
|
||||
|
||||
u32 check = v & ~mask;
|
||||
if (check != 0) Log::FileWarning(SCLY.GetSourceString(), SCLY.Tell() - 4, "Bitfield property \"" + pBitfieldTemp->Name() + "\" in struct \"" + pTemp->Name() + "\" has flags set that aren't in the template: " + StringUtil::ToHexString(check, true, true, 8));
|
||||
|
||||
break;
|
||||
}
|
||||
case eEnumProperty: {
|
||||
CEnumTemplate *pEnumTemp = static_cast<CEnumTemplate*>(pPropTmp);
|
||||
u32 ID = SCLY.ReadLong();
|
||||
|
@ -273,6 +288,22 @@ void CScriptLoader::LoadStructMP2(CInputStream& SCLY, CPropertyStruct *pStruct,
|
|||
break;
|
||||
}
|
||||
|
||||
case eBitfieldProperty: {
|
||||
CBitfieldProperty *pBitfieldCast = static_cast<CBitfieldProperty*>(pProp);
|
||||
pBitfieldCast->Set(SCLY.ReadLong());
|
||||
|
||||
// Validate
|
||||
u32 mask = 0;
|
||||
CBitfieldTemplate *pBitfieldTemp = static_cast<CBitfieldTemplate*>(pPropTemp);
|
||||
for (u32 iMask = 0; iMask < pBitfieldTemp->NumFlags(); iMask++)
|
||||
mask |= pBitfieldTemp->FlagMask(iMask);
|
||||
|
||||
u32 check = pBitfieldCast->Get() & ~mask;
|
||||
if (check != 0) Log::FileWarning(SCLY.GetSourceString(), SCLY.Tell() - 4, "Bitfield property \"" + pBitfieldTemp->Name() + "\" in struct \"" + pTemp->Name() + "\" has flags set that aren't in the template: " + StringUtil::ToHexString(check, true, true, 8));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case eEnumProperty: {
|
||||
CEnumProperty *pEnumCast = static_cast<CEnumProperty*>(pProp);
|
||||
CEnumTemplate *pEnumTemp = static_cast<CEnumTemplate*>(pPropTemp);
|
||||
|
|
|
@ -2,6 +2,31 @@
|
|||
#include "CWorldLoader.h"
|
||||
#include <Core/Log.h>
|
||||
|
||||
void CTemplateLoader::LoadBitFlags(tinyxml2::XMLElement *pElem, CBitfieldTemplate *pTemp, const std::string& templateName)
|
||||
{
|
||||
tinyxml2::XMLElement *pChild = pElem->FirstChildElement("bitflag");
|
||||
|
||||
while (pChild)
|
||||
{
|
||||
const char *kpMask = pChild->Attribute("mask");
|
||||
const char *kpName = pChild->Attribute("name");
|
||||
|
||||
if (kpMask && kpName)
|
||||
pTemp->mBitFlags.push_back(CBitfieldTemplate::SBitFlag(kpName, StringUtil::ToInt32(kpMask)));
|
||||
|
||||
else
|
||||
{
|
||||
std::string LogErrorBase = "Couldn't parse bit flag in " + templateName + "; ";
|
||||
|
||||
if (!kpMask && kpName) Log::Error(LogErrorBase + "no mask (" + kpName + ")");
|
||||
else if (kpMask && !kpName) Log::Error(LogErrorBase + "no name (mask " + kpMask + ")");
|
||||
else Log::Error(LogErrorBase + "no valid ID or name");
|
||||
}
|
||||
|
||||
pChild = pChild->NextSiblingElement("bitflag");
|
||||
}
|
||||
}
|
||||
|
||||
void CTemplateLoader::LoadEnumerators(tinyxml2::XMLElement *pElem, CEnumTemplate *pTemp, const std::string& templateName)
|
||||
{
|
||||
tinyxml2::XMLElement *pChild = pElem->FirstChildElement("enumerator");
|
||||
|
@ -18,8 +43,8 @@ void CTemplateLoader::LoadEnumerators(tinyxml2::XMLElement *pElem, CEnumTemplate
|
|||
{
|
||||
std::string LogErrorBase = "Couldn't parse enumerator in " + templateName + "; ";
|
||||
|
||||
if (!kpID && kpName) Log::Error(LogErrorBase + "no valid ID (" + kpName + ")");
|
||||
if (kpID && !kpName) Log::Error(LogErrorBase + "no valid name (ID " + kpID + ")");
|
||||
if (!kpID && kpName) Log::Error(LogErrorBase + "no valid ID (" + kpName + ")");
|
||||
else if (kpID && !kpName) Log::Error(LogErrorBase + "no valid name (ID " + kpID + ")");
|
||||
else Log::Error(LogErrorBase + "no valid ID or name");
|
||||
}
|
||||
|
||||
|
@ -193,15 +218,54 @@ CPropertyTemplate* CTemplateLoader::LoadPropertyTemplate(tinyxml2::XMLElement *p
|
|||
|
||||
LoadEnumerators(pRoot, pEnum, kpTemplateStr );
|
||||
}
|
||||
|
||||
// Name
|
||||
if (!name.empty())
|
||||
pEnum->mPropName = name;
|
||||
|
||||
return pEnum;
|
||||
}
|
||||
|
||||
// Name
|
||||
if (!name.empty())
|
||||
pEnum->mPropName = name;
|
||||
|
||||
return pEnum;
|
||||
}
|
||||
|
||||
|
||||
// Load Bitfield
|
||||
else if (strcmp(pElem->Name(), "bitfield") == 0)
|
||||
{
|
||||
CBitfieldTemplate *pBitfield = new CBitfieldTemplate(ID);
|
||||
|
||||
// Embedded
|
||||
if (!pElem->NoChildren())
|
||||
LoadBitFlags(pElem, pBitfield, templateName);
|
||||
|
||||
// Template
|
||||
else if (kpTemplateStr)
|
||||
{
|
||||
std::string tempPath = mMasterDir + kpTemplateStr;
|
||||
|
||||
tinyxml2::XMLDocument bitfieldXML;
|
||||
bitfieldXML.LoadFile(tempPath.c_str());
|
||||
|
||||
if (bitfieldXML.Error())
|
||||
Log::Error("Couldn't open bitfield XML: " + mMasterDir + kpTemplateStr);
|
||||
|
||||
else
|
||||
{
|
||||
tinyxml2::XMLElement *pRoot = bitfieldXML.FirstChildElement("bitfield");
|
||||
pBitfield->mSourceFile = kpTemplateStr;
|
||||
|
||||
if (pRoot->Attribute("name"))
|
||||
pBitfield->mPropName = pRoot->Attribute("name");
|
||||
|
||||
LoadBitFlags(pRoot, pBitfield, kpTemplateStr);
|
||||
}
|
||||
}
|
||||
|
||||
// Name
|
||||
if (!name.empty())
|
||||
pBitfield->mPropName = name;
|
||||
|
||||
return pBitfield;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ class CTemplateLoader
|
|||
CTemplateLoader(const std::string& templatesDir) : mTemplatesDir(templatesDir) {}
|
||||
|
||||
// Load Property
|
||||
void LoadBitFlags(tinyxml2::XMLElement *pElem, CBitfieldTemplate *pTemp, const std::string& templateName);
|
||||
void LoadEnumerators(tinyxml2::XMLElement *pElem, CEnumTemplate *pTemp, const std::string& templateName);
|
||||
void LoadStructProperties(tinyxml2::XMLElement *pElem, CStructTemplate *pTemp, const std::string& templateName);
|
||||
CPropertyTemplate* LoadPropertyTemplate(tinyxml2::XMLElement *pElem, const std::string& templateName);
|
||||
|
|
|
@ -101,6 +101,7 @@ CPropertyStruct* CPropertyStruct::CopyFromTemplate(CStructTemplate *pTemp)
|
|||
case eShortProperty: pProp = new CShortProperty(0); break;
|
||||
case eLongProperty: pProp = new CLongProperty(0); break;
|
||||
case eEnumProperty: pProp = new CEnumProperty(0); break;
|
||||
case eBitfieldProperty: pProp = new CBitfieldProperty(0); break;
|
||||
case eFloatProperty: pProp = new CFloatProperty(0.f); break;
|
||||
case eStringProperty: pProp = new CStringProperty(""); break;
|
||||
case eVector3Property: pProp = new CVector3Property(CVector3f::skZero); break;
|
||||
|
|
|
@ -60,6 +60,7 @@ typedef __CProperty<char, eByteProperty> CByteProperty;
|
|||
typedef __CProperty<short, eShortProperty> CShortProperty;
|
||||
typedef __CProperty<long, eLongProperty> CLongProperty;
|
||||
typedef __CProperty<long, eEnumProperty> CEnumProperty;
|
||||
typedef __CProperty<long, eBitfieldProperty> CBitfieldProperty;
|
||||
typedef __CProperty<float, eFloatProperty> CFloatProperty;
|
||||
typedef __CProperty<std::string, eStringProperty> CStringProperty;
|
||||
typedef __CProperty<CVector3f, eVector3Property> CVector3Property;
|
||||
|
|
|
@ -8,6 +8,7 @@ EPropertyType PropStringToPropEnum(std::string prop)
|
|||
if (prop == "short") return eShortProperty;
|
||||
if (prop == "long") return eLongProperty;
|
||||
if (prop == "enum") return eEnumProperty;
|
||||
if (prop == "bitfield") return eBitfieldProperty;
|
||||
if (prop == "float") return eFloatProperty;
|
||||
if (prop == "string") return eStringProperty;
|
||||
if (prop == "color") return eColorProperty;
|
||||
|
@ -29,6 +30,7 @@ std::string PropEnumToPropString(EPropertyType prop)
|
|||
case eShortProperty: return "short";
|
||||
case eLongProperty: return "long";
|
||||
case eEnumProperty: return "enum";
|
||||
case eBitfieldProperty: return "bitfield";
|
||||
case eFloatProperty: return "float";
|
||||
case eStringProperty: return "string";
|
||||
case eColorProperty: return "color";
|
||||
|
|
|
@ -142,6 +142,54 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class CBitfieldTemplate : public CPropertyTemplate
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
struct SBitFlag
|
||||
{
|
||||
std::string Name;
|
||||
u32 Mask;
|
||||
|
||||
SBitFlag(const std::string& _name, u32 _mask)
|
||||
: Name(_name), Mask(_mask) {}
|
||||
};
|
||||
std::vector<SBitFlag> mBitFlags;
|
||||
std::string mSourceFile;
|
||||
|
||||
public:
|
||||
CBitfieldTemplate(u32 ID)
|
||||
: CPropertyTemplate(ID)
|
||||
{
|
||||
mPropType = eBitfieldProperty;
|
||||
}
|
||||
|
||||
CBitfieldTemplate(const std::string& name, u32 ID)
|
||||
: CPropertyTemplate(eBitfieldProperty, name, ID)
|
||||
{}
|
||||
|
||||
EPropertyType Type() const
|
||||
{
|
||||
return eBitfieldProperty;
|
||||
}
|
||||
|
||||
u32 NumFlags()
|
||||
{
|
||||
return mBitFlags.size();
|
||||
}
|
||||
|
||||
std::string FlagName(u32 index)
|
||||
{
|
||||
return mBitFlags[index].Name;
|
||||
}
|
||||
|
||||
u32 FlagMask(u32 index)
|
||||
{
|
||||
return mBitFlags[index].Mask;
|
||||
}
|
||||
};
|
||||
|
||||
class CStructTemplate : public CPropertyTemplate
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
|
|
|
@ -9,11 +9,12 @@ enum EPropertyType
|
|||
eByteProperty,
|
||||
eShortProperty,
|
||||
eLongProperty,
|
||||
eEnumProperty,
|
||||
eBitfieldProperty,
|
||||
eFloatProperty,
|
||||
eStringProperty,
|
||||
eVector3Property,
|
||||
eColorProperty,
|
||||
eEnumProperty,
|
||||
eFileProperty,
|
||||
eStructProperty,
|
||||
eArrayProperty,
|
||||
|
|
|
@ -157,6 +157,34 @@ void WPropertyEditor::CreateEditor()
|
|||
break;
|
||||
}
|
||||
|
||||
// Bitfield - QGroupBox containing QCheckBoxes
|
||||
case eBitfieldProperty:
|
||||
{
|
||||
CBitfieldProperty *pBitfieldCast = static_cast<CBitfieldProperty*>(mpProperty);
|
||||
CBitfieldTemplate *pTemplate = static_cast<CBitfieldTemplate*>(pBitfieldCast->Template());
|
||||
long value = pBitfieldCast->Get();
|
||||
|
||||
QGroupBox *pGroupBox = new QGroupBox(this);
|
||||
QVBoxLayout *pBitfieldLayout = new QVBoxLayout(pGroupBox);
|
||||
pBitfieldLayout->setContentsMargins(5,5,5,5);
|
||||
pGroupBox->setLayout(pBitfieldLayout);
|
||||
pGroupBox->setTitle(QString::fromStdString(pBitfieldCast->Name()));
|
||||
mUI.PropertyName->hide();
|
||||
|
||||
for (u32 iFlag = 0; iFlag < pTemplate->NumFlags(); iFlag++)
|
||||
{
|
||||
std::string flagName = pTemplate->FlagName(iFlag);
|
||||
long mask = pTemplate->FlagMask(iFlag);
|
||||
|
||||
QCheckBox *pCheckBox = new QCheckBox(QString::fromStdString(flagName), pGroupBox);
|
||||
pCheckBox->setChecked((value & mask) != 0);
|
||||
pBitfieldLayout->addWidget(pCheckBox);
|
||||
}
|
||||
|
||||
mUI.EditorWidget = pGroupBox;
|
||||
break;
|
||||
}
|
||||
|
||||
// Float - WDraggableSpinBox
|
||||
case eFloatProperty:
|
||||
{
|
||||
|
@ -280,6 +308,7 @@ void WPropertyEditor::CreateEditor()
|
|||
|
||||
// For some reason setting a minimum size on group boxes flattens it...
|
||||
if ((mpProperty->Type() != eStructProperty) &&
|
||||
(mpProperty->Type() != eBitfieldProperty) &&
|
||||
(mpProperty->Type() != eVector3Property) &&
|
||||
(mpProperty->Type() != eAnimParamsProperty))
|
||||
{
|
||||
|
@ -336,6 +365,29 @@ void WPropertyEditor::UpdateEditor()
|
|||
break;
|
||||
}
|
||||
|
||||
case eBitfieldProperty:
|
||||
{
|
||||
CBitfieldProperty *pBitfieldCast = static_cast<CBitfieldProperty*>(mpProperty);
|
||||
CBitfieldTemplate *pTemplate = static_cast<CBitfieldTemplate*>(pBitfieldCast->Template());
|
||||
QGroupBox *pGroupBox = static_cast<QGroupBox*>(mUI.EditorWidget);
|
||||
|
||||
QObjectList ChildList = pGroupBox->children();
|
||||
long value = pBitfieldCast->Get();
|
||||
u32 propNum = 0;
|
||||
|
||||
foreach (QObject *pObj, ChildList)
|
||||
{
|
||||
if (pObj != pGroupBox->layout())
|
||||
{
|
||||
u32 mask = pTemplate->FlagMask(propNum);
|
||||
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pObj);
|
||||
pCheckBox->setChecked((value & mask) != 0);
|
||||
propNum++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case eFloatProperty:
|
||||
{
|
||||
CFloatProperty *pFloatCast = static_cast<CFloatProperty*>(mpProperty);
|
||||
|
|
Loading…
Reference in New Issue