-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reusable object templates #1587
Reusable object templates #1587
Conversation
5bb77d2
to
408c31e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You've made a good start! To avoid building up a too large pull request, I think we should agree on certain "check points" and set the target branch to the wip/templates
branch that I just created. This way, we can merge pull requests there until the whole feature is ready to be merged into master
.
I would suggest the first checkpoint to be roughly the functionality you've started with here, in addition to the following bits:
- Finish the saving and loading of tileset references.
- Finish the implementations of the
TemplateGroupDocument
methods. - Using a temporary
TemplateGroupDocument
inMapDocument::saveSelectedObjectsAsTemplateGroup
for testing its functionality. - Working on the feedback I put in comments (probably including the addition of a
Template
class, which I think should have a "name" and "id" independently of theMapObject
it refers to). - Adding the license header to new files.
Then, I think we have a good base to continue to the next steps like implementing the Templates dock.
src/libtiled/mapreader.cpp
Outdated
|
||
MapObject *object = new MapObject(name, type, {0, 0}, size); | ||
|
||
readObjectData(object); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you decide to not use the following format?
<template>
<object ...>
...
</object>
</template>
Such that, you could re-use the entire readObject
function within the readTemplate
function and avoid the need for readObjectData
? It would also allow a separation of concerns, like a template.name
attribute could be used as name of the template, whereas object.name
would be the name of the instantiated object.
As an extension of this, I think you need to add a Template
class, which points to its object using a member. TemplateGroup::addObject
then becomes TemplateGroup::addTemplate
. This may also provide a good place to keep back-references to instances of the template, in order to know what to update when the object is changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, I didn't understand what you meant, I thought you referred to the template group as template.
So just to be clear the format will look like this
<templategroup ...>
<template ...>
<object ...>
...
</object ...>
</template ...>
<template ...>
<object ...>
...
</object ...>
</template>
</templategroup>
This looks more effective, I will update it and the template class makes more sense now.
And for writing, is there a better way other than creating a new function just to prevent writing the id and the coordinates? Does sending a parameter to tell it whether to write them or not be appropriate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be fine to prevent the writing of the ID by just making sure it is 0 and adding a check for this in MapWriterPrivate::writeObject
. For now, I would not bother with preventing the writing of the position.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay that would allow more code reuse, but what do you mean by setting id to 0, wouldn't that change the original object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, only the object owned by the template, which should be a copy, would have its ID set to 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay great, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
template
is a keyword in C++, would objectTemplate
as the name of the class be fine?
src/libtiled/mapreader.cpp
Outdated
{ | ||
QFile file(fileName); | ||
if (!d->openFile(&file)) { | ||
return new TemplateGroup(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding style: please leave out ()
when constructing classes without passing any constructor arguments.
In addition, it seems weird to return an empty constructed template group when the file could not be opened. Consider if you can just return nullptr
.
src/libtiled/mapwriter.cpp
Outdated
writer.writeStartElement(QLatin1String("templategroup")); | ||
|
||
if (mDtdEnabled) { | ||
writer.writeDTD(QLatin1String("<!DOCTYPE map SYSTEM \"" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The map
part of the DTD should match the root element, so it should be templategroup
. Of course, eventually we'd have to update the DTD as well then. I'm not sure if DTD validation is really useful though.
src/libtiled/mapwriter.h
Outdated
void writeTemplateGroup(const QList<MapObject *> &mapObjects, QIODevice *device, | ||
const QString &path = QString()); | ||
|
||
bool writeTemplateGroup(const QList<MapObject *> &mapObjects, const QString &fileName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you already have a TemplateGroup
class, I would suggest to use that here instead of a plain list of objects.
src/tiled/abstractobjecttool.cpp
Outdated
@@ -259,6 +264,8 @@ void AbstractObjectTool::showContextMenu(MapObjectItem *clickedObjectItem, | |||
isResizedTileObject)); | |||
} | |||
|
|||
menu.addAction(tr("Save As A Template Group"), this, SLOT(saveSelectedObjectsAsATemplateGroup())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's grammatically fine and easier to read when you leave out the "A" here (also in the function name).
src/tiled/mapdocument.h
Outdated
@@ -43,6 +43,7 @@ class Map; | |||
class MapObject; | |||
class MapRenderer; | |||
class MapFormat; | |||
class TemplateGroupFormat; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This forward declaration seems not needed here (maybe not anymore).
src/tiled/templategroupdocument.cpp
Outdated
using namespace Tiled; | ||
using namespace Tiled::Internal; | ||
|
||
TemplateGroupDocument::TemplateGroupDocument(TemplateGroup templateGroup, const QString &fileName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably the template group should be passed in as a pointer instead.
cbf91a9
to
d004f38
Compare
I've updated the format, added the tileset references to the templategroup and fixed some review points. I'm working on changing the writing function to work directly on a template group instead of an object list, and will add more information to the template group and the templates. |
I updated the saving function and will start working on the I added a name to To prevent writing the ID and the coordinates of the |
Extracted some code from readObject function
c8dabf0
to
69a2353
Compare
Reduce code duplication in writing objects and templates
- Remove double included QDebug - Fix some warnings - Remove writeObject function from TmxMapFormat - Print the size of the read objects for testing - Formatting - Rename the saving function - Remove some comments - Change the name of the saved file
- Rename TtxTemplateFormat to TtxTemplateGroupFormat - Review related updates - Return nullptr when a template group file can't be opened - Remove wrong DTD link - Rename saving function from save as a template group to save as template group - Use template group pointer in temlate group document constructer - Remove unneeded forward declaration
Added objectTemplate class, and used the object reading and writing functions.
Also added extra attributes to the template group and the object template and updated saving, reading and testing accordingly.
69a2353
to
7bdcec9
Compare
I implemented the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only some minor comments, then I will merge this. I've tested it shortly and it seemed to work well!
src/tiled/templategroupdocument.cpp
Outdated
{ | ||
QString displayName = mTemplateGroup->name(); | ||
|
||
if(displayName.isEmpty()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding style: please put a space after if
.
src/tiled/tmxmapformat.cpp
Outdated
mError.clear(); | ||
|
||
MapReader reader; | ||
TemplateGroup *templateGroup = reader.readTemplateGroup(fileName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding style: one space too many after =
.
src/tiled/mapdocument.cpp
Outdated
/** | ||
* Currently, this is the entry point for testing templates, | ||
* it creates a templateGroup from the selected objects except the last object, | ||
* then creates a templatGroupDocument from the templateGroup, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: templatGroupDocument (also, I think it would be better to match the casing with the class name).
|
||
QString fileName = QLatin1String("templateGroup.ttx"); | ||
|
||
TemplateGroupDocument *templateGroupDocument = new TemplateGroupDocument(templateGroup, fileName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No change required, but just to note, that to have less repetition I am often using auto
for such lines these days, since the type is completely obvious:
auto templateGroupDocument = new TemplateGroupDocument(templateGroup, fileName);
This pull request is about the reusable object templates project in GSoC 2017, addresses #70 .
The entry point for testing is selecting some objects and choosing "Save as a template group", the selected objects will be saved to a file, then the file will be immediately read and the sizes of the saved templates will be printed, this is just for testing purposes.
When saving tile objects, the tileset info will be saved as well, this encourages having standalone template groups that can be used across multiple objects, although for now, when reading the file, the tilesets are ignored.
The next step will be creating a template group document that will allow loading the template group into tiled.
Code wise, I've followed tileset format and map format for creating the new classes, the template group is till now similar to object group, maybe I will need to create a new class for a template instead of using the object class.
Reading and writing reuses some of the available code, I had to extract some of the object reading and writing code (the part that handles different types of objects), otherwise things are pretty similar to writing object groups albeit with some changes like not writing the coordinates of the object or its ID as they won't be relevant when creating new copies of the template.
So currently this hypothetical use case is simple and some parts of the code are not complete, I think having the template group ready and loading it into Tiled will require doing more checking and will reveal more cases that require better handling.