Part 12: Wall ornates - Part 1
Downloads
The ornates
<?xml version="1.0" encoding="ISO-8859-1"?>
<ornates>
<ornate name="None">
</ornate>
<ornate name="Manacles">
<image_front>Manacles_front.png</image_front>
<image_side>Manacles_side.png</image_side>
<pos_front x="66" y="71"/>
<pos_side x="30" y="73"/>
</ornate>
</ornates>
We have the graphics files for our 2 sprites which correspond to the nearest walls, and their positions on the screen.
Additional parameters in "walls.xml"
<?xml version="1.0" encoding="ISO-8859-1"?>
<walls>
<wall name="Nothing">
</wall>
<wall name="Simple">
<image>Wall.png</image>
<param type="ornate">Ornate</param>
</wall>
</walls>
At the moment, we only have one parameter type. We define it in an enum so that the code will be more readable when we will have more types:
enum EParamType
{
eParamOrnate = 0,
};
To store the parameters names in the code, we define a vector of vectors of CParamType structures in the map:
struct CParamType
{
EParamType mType;
QString mName;
};
class CMap
{
[...]
std::vector<std::vector<CParamType>> mWallsParams; // list of the params for each type of wall
[...]
};
There are 2 vectors because:
void CEditor::readWallsDB(QString fileName)
{
[...]
while(!wall.isNull())
{
std::vector paramsTypesList;
if (wall.tagName() == "wall")
{
CWallData newWall;
[...]
while(!wallInfo.isNull())
{
if (wallInfo.tagName() == "image")
{
[...]
}
else if (wallInfo.tagName() == "param")
{
QString paramType = wallInfo.attribute("type");
if (paramType == "ornate")
{
CParamType newParamType;
newParamType.mType = eParamOrnate;
newParamType.mName = wallInfo.text();
paramsTypesList.push_back(newParamType);
}
}
wallInfo = wallInfo.nextSibling().toElement();
}
wallsDatas.push_back(newWall);
map.mWallsParams.push_back(paramsTypesList);
}
wall = wall.nextSibling().toElement();
}
}
The parameters values
class CParam
{
public:
EParamType mType;
};
class CParamOrnate : CParam
{
public:
CParamOrnate();
uint8_t mValue;
};
The CWall class will contain a vector of those CParams:
std::vector<CParam*> mParams;
But in fact the CWall class has completely changed...
class CWall
{
public:
CWall();
virtual ~CWall();
void setType(uint8_t type);
uint8_t getType();
CWall& operator=(CWall& rhs);
void load(FILE* handle);
void save(FILE* handle);
std::vector<CParam*> mParams;
private:
void deleteParams();
uint8_t mType;
};
So let me explain all those functions.
uint8_t CWall::getType()
{
return mType;
}
deleteParams() clears the parameters list:
void CWall::deleteParams()
{
for (size_t i = 0; i < mParams.size(); ++i)
delete mParams[i];
mParams.clear();
}
The setType() function changes the value of mType. And as I said before it reallocates the parameters for this type:
void CWall::setType(uint8_t type)
{
if (mType == type)
return;
mType = type;
// allocate the params
deleteParams();
std::vector& paramTypes = map.mWallsParams[type];
for (size_t i = 0; i < paramTypes.size(); ++i)
{
CParam* newParam = NULL;
switch (paramTypes[i].mType)
{
case eParamOrnate:
newParam = (CParam*)(new CParamOrnate);
break;
default:
break;
}
mParams.push_back(newParam);
}
}
So I had to change every place in the code where the mType of the wall was used or modified to replace them with these set and get functions.
Creating the widgets
import QtQuick 2.5
import QtQuick.Controls 1.4
Label {
height: 20
text: qsTr("Test")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
renderType: Text.QtRendering
}
... and "ParamComboBox.qml"...
import QtQuick 2.5
import QtQuick.Controls 1.4
ComboBox {
property int identifier: -1
currentIndex: -1
onCurrentIndexChanged: bridge.setSelParamCombo(identifier, currentIndex);
}
We will add these widget to the grids in the differents selections "sheets" so, we have to get pointers to these grids in "main.cpp":
QQuickItem* tileSelGrid;
QQuickItem* wallSelGrid;
QQuickItem* objSelGrid;
[...]
QObject *rootObject = engine.rootObjects().first();
tileSelGrid = qobject_cast(rootObject->findChild("tSelGrid"));
wallSelGrid = qobject_cast(rootObject->findChild("wSelGrid"));
objSelGrid = qobject_cast(rootObject->findChild("oSelGrid"));
Our widgets will be created in the toolSelect() function, every time we select a single wall:
void CEditor::toolSelect()
{
if (bridge.leftPressed == true)
{
[...]
switch (bridge.mTabIndex)
{
[...]
case eTabWalls:
if (isSelectSingleWall() == true)
{
EWallSide side = getWallSideAbs(mSelectStart);
uint8_t type = map.getTile(rect.tl)->mWalls[side].getType();
bridge.set_selWallType(type);
deleteParamItems(&mWallParamItems);
addWallParamsItems(type);
}
break;
default:
break;
}
bridge.updateQMLImage();
}
}
[...]
void CEditor::addWallParamsItems(uint8_t type)
{
CVec2 pos = mSelectStart / TILE_SIZE;
EWallSide side = getWallSideAbs(mSelectStart);
CWall* wall = &map.getTile(pos)->mWalls[side];
std::vector<CParamType>& sourceList = map.mWallsParams[type];
for (size_t i = 0; i < sourceList.size(); ++i)
{
CParam* param = wall->mParams[i];
if (sourceList[i].mType == eParamOrnate)
{
CParamOrnate* par = (CParamOrnate*)param;
addLabel(wallSelGrid, sourceList[i].mName + ":", &mWallParamItems);
addComboBox(wallSelGrid, bridge.ornatesList, &mWallParamItems, i, par->mValue);
}
}
}
And here are the functions that really loads the qml files and creates the widgets from them. It's a little bit of "Qt magic".
//---------------------------------------------------------------------------------------------
QQuickItem* CEditor::loadQml(QString file, QQuickItem* parent)
{
QQmlComponent component(myQmlEngine, QUrl(file));
QQuickItem* object = qobject_cast<QQuickItem*>(component.create());
QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
object->setParent(parent);
object->setParentItem(parent);
return object;
}
//---------------------------------------------------------------------------------------------
void CEditor::addLabel(QQuickItem* parent, QString text, std::vector<QQuickItem *> *list)
{
QQuickItem* object = loadQml("qrc:/ParamLabel.qml", parent);
object->setProperty("text", QVariant(text));
list->push_back(object);
}
//---------------------------------------------------------------------------------------------
void CEditor::addComboBox(QQuickItem* parent, QStringList& values, std::vector<QQuickItem*>* list, int id, int index)
{
QQuickItem* object = loadQml("qrc:/ParamComboBox.qml", parent);
object->setProperty("model", QVariant(values));
object->setProperty("identifier", QVariant(id));
object->setProperty("currentIndex", QVariant(index));
list->push_back(object);
}
Well that was a lot of work, but now we have a way to add various parameter for a given wall type.