Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Template instances #1623

Merged
merged 11 commits into from
Jul 13, 2017
Merged

Template instances #1623

merged 11 commits into from
Jul 13, 2017

Conversation

thabetx
Copy link
Contributor

@thabetx thabetx commented Jun 23, 2017

This is the third checkpoint in the reusable object templates project, it will be mainly concerned with reading template instance in a map.

The format will look like this

 <templategroup firsttid="1" source="group1.ttx"/>
 <templategroup firsttid="11" source="group2.ttx"/>

 <object id="66" tid="2" x="191" y="342"/>

The instance in the map file would be the same as an object except that it would have an extra attribute similar to the gid called the tid standing for template id. Template ids would work like tileset ids, the map assigns the firsttid to each template group and the template manager would resolve those ids.

If a template object has properties they will override the template.

  • Create TemplatesManager to aid in mapping.
  • Create the tid mapping functionality.
  • Handle reading errors.
  • Write template group references inside the map.
  • Write template instances inside the map.
  • Reduce redundant data when writing.

Currently the pull request is focused on reading an instance but may be expanded to also cover creation.

@thabetx thabetx force-pushed the template-instances branch 2 times, most recently from 805e8a1 to e5d790a Compare June 26, 2017 12:06
@thabetx
Copy link
Contributor Author

thabetx commented Jun 26, 2017

The code can now read template instances and load them into the map. I will do more testing and handle possible errors.

@thabetx thabetx force-pushed the template-instances branch from e5d790a to 0d54859 Compare June 27, 2017 01:05
Will also handle some reading errors.
@thabetx thabetx force-pushed the template-instances branch 3 times, most recently from 7a1fa2a to 812d0aa Compare June 27, 2017 23:23
Also added a nextTemplateId property to the template to be used when saving or adding a new template.
@thabetx thabetx force-pushed the template-instances branch from 812d0aa to ee489b0 Compare June 28, 2017 08:15
@thabetx thabetx force-pushed the template-instances branch 4 times, most recently from e1bf477 to 89b8aeb Compare July 1, 2017 15:37
Copy link
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall, but I found some issues.


CellProperty = 1 << 8,
SizeProperty = 1 << 9,
shapeProperty = 1 << 10
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming: ShapeProperty

}

if (id != 0)
if (id != 0 && !isTemplateInstance)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template instances do still need their ID.

if (it.value() == templateGroup)
return it.key();
}
return 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function can be written as:

return mFirstTidToTemplateGroup.key(templateGroup);

It should also be marked const.


ObjectTemplate *TidMapper::tidToTemplate(unsigned tid, bool &ok) const
{
ObjectTemplate *objectTemplate;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be initialized to nullptr, to ensure a consistent return value in case of failure in addition to setting ok to false.

objectTemplate = templateGroup->templateAt(index);
} else {
ok = false;
objectTemplate = nullptr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When properly initialized, we don't need to set it to nullptr here.

w.writeAttribute(QLatin1String("tid"), QString::number(tid));
}

if (id != 0 && !isTemplateInstance)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template instances need to write their ID as well.

w.writeAttribute(QLatin1String("visible"), QLatin1String("0"));

writeProperties(w, mapObject.properties());
if (!isTemplateInstance)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Properties should always be written, since this will only include overridden values and any properties only added to the instance.

inline void ObjectTemplateModel::setTemplateDocuments(const TemplateDocuments &templateDocuments)
{ mTemplateDocuments = templateDocuments; }
inline void ObjectTemplateModel::setTemplateDocuments(TemplateDocuments &templateDocuments)
{ mTemplateDocuments = &templateDocuments; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mTemplateDocuments should not be a pointer. Rather, just store the list here by value and when you need it in the TemplatesDock, have it call ObjectTemplateModel::templateDocuments and remove TemplatesDock::mTemplateDocuments. The function should take const TemplateDocuments &templateDocuments.

Also, since this affects the model, it should call beginResetModel and endResetModel, even though currently the function may only be called while the model is not yet used by a view, this could change later on.

It should probably also own the documents, so it should call qDeleteAll(mTemplateDocuments) before the assignment, and this should be added to the destructor (instead of doing it in TemplatesDock).


inline const TemplateDocuments ObjectTemplateModel::templateDocuments() const
{ return mTemplateDocuments; }
{ return *mTemplateDocuments; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should return const TemplateDocuments &.

manager->setTemplateGroups(templateGroups);
}

TemplatesDock::~TemplatesDock() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coding style: { should be on the next line.

@thabetx thabetx force-pushed the template-instances branch from 89b8aeb to 2b26d24 Compare July 4, 2017 12:34
@@ -49,6 +52,7 @@ private slots:
void retranslateUi();

TemplatesView *mTemplatesView;
TemplateDocuments mTemplateDocuments;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems you forgot to remove this member, and the above include?

@thabetx thabetx force-pushed the template-instances branch 2 times, most recently from e1f5039 to 6e4f3df Compare July 4, 2017 13:28
Copy link
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments.

mMapObjects[i]->flip(mFlipDirection, mObjectsCenter);

mMapObjects[i]->setPropertyChanged(MapObject::CellProperty, mNewCellStates[i]);
mMapObjects[i]->setPropertyChanged(MapObject::RotationProperty, mNewCellStates[i]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mNewCellStates should be mNewRotationStates

}
}

delete oldTemplateGroup;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe somebody should delete the old template group, but it's not the map.

case TilesetTileImageSource:
return nullptr;
case TemplateGroupReference:
return _templateGroup;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, that is a lot of lines for writing:

return type == TemplateGroupReference ? _templateGroup : nullptr;

:-)

link._templateGroup = templateGroup;
mBrokenLinks.append(link);
} else {
processTemplateGroup(templateGroup);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This else makes no sense, because it does essentially the same as the code above, just without the check on the file name being empty (which should be there, I guess).

@@ -404,6 +460,7 @@ void BrokenLinksWidget::selectionChanged()
mLocateButton->setEnabled(!selection.isEmpty());

bool isTileset = qobject_cast<TilesetDocument*>(mBrokenLinksModel->document()) != nullptr;
bool isTemplateGroup = qobject_cast<TemplateGroupDocument*>(mBrokenLinksModel->document()) != nullptr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The broken links model document can never be a template group document, since we don't currently have a template group editor.

if (isTemplateGroup)
mLocateButton->setText(tr("Locate File..."));
else
mLocateButton->setText(tr("Open Template Group..."));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The button should always read "Locate File..." at this point, since we can't open template groups directly.

@thabetx thabetx force-pushed the template-instances branch 2 times, most recently from 6f185c8 to 5172938 Compare July 5, 2017 15:17
@bjorn
Copy link
Member

bjorn commented Jul 6, 2017

@thabetx Looks like your last commit should go to the 1.0 branch. :-)

@thabetx
Copy link
Contributor Author

thabetx commented Jul 6, 2017

Okay, I will test it on master.

@thabetx thabetx force-pushed the template-instances branch from 2220c71 to 419444b Compare July 6, 2017 12:41
Copy link
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Numerous small comments but overal I think it's looking pretty solid. Let's aim for merging this as soon as possible so we can have a new PR for the actual instantiation.

return true;
}

QList<Tiled::MapObject *> Map::replaceTemplateGroup(TemplateGroup *oldTemplateGroup, TemplateGroup *newTemplateGroup)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MapObject does not need to be fully qualified here.

@@ -33,6 +33,7 @@
#include "map.h"
#include "objectgroup.h"
#include "tile.h"
#include "templatemanager.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can include templategroup.h instead of templatemanager.h, since the manager isn't actually used.

@@ -921,41 +963,74 @@ MapObject *MapReaderPrivate::readObject()
const QPointF pos(x, y);
const QSizeF size(width, height);

MapObject *object = new MapObject(name, type, pos, size);
MapObject *object = new MapObject;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could still use the previous constructor, and then just initialize the flags as follows?

object->setPropertyChanged(MapObject::NameProperty, !name.isEmpty());
object->setPropertyChanged(MapObject::TypeProperty, !type.isEmpty());
object->setPropertyChanged(MapObject::SizeProperty, !size.isEmpty());

Would just be a bit shorter.

ok = true;

if (!templateGroup->loaded())
templateGroup->updateMaxId(id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can include this in the else of the previous condition.

QMapIterator<unsigned, TemplateGroup*> it(mFirstTidToTemplateGroup);

while (it.hasNext()) {
it.next();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation is off by 2.

for (int i = 0; i < mMapObjects.size(); ++i) {
mMapObjects[i]->flip(mFlipDirection, mObjectsCenter);

mMapObjects[i]->setPropertyChanged(MapObject::CellProperty, mNewCellStates[i]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little concerned about this. I think flipping some tile object is not actually expected to override the referenced tile, but just its flipped state. I think it's not very important to deal with this now, but it's something to keep in mind.

MapDocument *mapDocument = MapDocument::load(fileName, mapFormat, &error);
document = mapDocument;

bool hasNonEmbeddedTemplateGroups;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable is missing an initialization. Not that it matters, because the variable isn't really used. Remove?

auto changedObjects = mMap->replaceTemplateGroup(oldTemplateGroup, templateGroup);

// Update the objects in the map scene
emit(objectsChanged(changedObjects));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coding style: please use the empty emit macro as follows:

emit objectsChanged(changedObjects);

@@ -45,7 +45,7 @@ TemplateGroupDocument::TemplateGroupDocument(TemplateGroup *templateGroup, const
: Document(TemplateGroupDocumentType, fileName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this fileName also be changed to mTemplateGroup->fileName()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so. The template group should always contain the file name, so the constructor arguments can be the template group only.

CellProperty = 1 << 8,
SizeProperty = 1 << 9,
ShapeProperty = 1 << 10,
RotationProperty = 1 << 11
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you've added several entries here, I'm getting warnings in MapObject::setMapObjectProperty and MapObject::mapObjectProperty. I think size and rotation could simply be handled, but "shape" and "cell" are too special and it should probably catch those with a Q_ASSERT(false);.

@thabetx thabetx force-pushed the template-instances branch from a65dbd2 to eff51e6 Compare July 12, 2017 02:44
thabetx added 3 commits July 12, 2017 06:04
Also created the sync function which synchronizes the properties of a template instance with the base template.
@thabetx thabetx force-pushed the template-instances branch from eff51e6 to 92d06ca Compare July 12, 2017 04:24
@thabetx thabetx force-pushed the template-instances branch from 92d06ca to f6251ae Compare July 12, 2017 11:53
@bjorn bjorn merged commit f6251ae into mapeditor:wip/templates Jul 13, 2017
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants