diff --git a/src/libtiled/grouplayer.cpp b/src/libtiled/grouplayer.cpp new file mode 100644 index 0000000000..39da70cd43 --- /dev/null +++ b/src/libtiled/grouplayer.cpp @@ -0,0 +1,130 @@ +/* + * grouplayer.cpp + * Copyright 2017, Thorbjørn Lindeijer + * + * This file is part of Tiled. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "grouplayer.h" + +#include "map.h" + +namespace Tiled { + +GroupLayer::GroupLayer(const QString &name, int x, int y): + Layer(GroupLayerType, name, x, y) +{ +} + +GroupLayer::~GroupLayer() +{ + qDeleteAll(mLayers); +} + +void GroupLayer::addLayer(Layer *layer) +{ + adoptLayer(layer); + mLayers.append(layer); +} + +void GroupLayer::insertLayer(int index, Layer *layer) +{ + adoptLayer(layer); + mLayers.insert(index, layer); +} + +void GroupLayer::adoptLayer(Layer *layer) +{ + layer->setMap(map()); + + if (map()) + if (ObjectGroup *group = layer->asObjectGroup()) + map()->initializeObjectIds(*group); +} + +Layer *GroupLayer::takeLayerAt(int index) +{ + Layer *layer = mLayers.takeAt(index); + layer->setMap(nullptr); + return layer; +} + +void GroupLayer::setMap(Map *map) +{ + // todo: What about initializing object IDs? + Layer::setMap(map); + for (Layer *layer : mLayers) + layer->setMap(map); +} + +bool GroupLayer::isEmpty() const +{ + return mLayers.isEmpty(); +} + +QSet GroupLayer::usedTilesets() const +{ + QSet tilesets; + + for (const Layer *layer : mLayers) + tilesets |= layer->usedTilesets(); + + return tilesets; +} + +bool GroupLayer::referencesTileset(const Tileset *tileset) const +{ + for (const Layer *layer : mLayers) + if (layer->referencesTileset(tileset)) + return true; + + return false; +} + +void GroupLayer::replaceReferencesToTileset(Tileset *oldTileset, Tileset *newTileset) +{ + const auto &children = mLayers; + for (Layer *layer : children) + layer->replaceReferencesToTileset(oldTileset, newTileset); +} + +bool GroupLayer::canMergeWith(Layer *) const +{ + // Merging group layers would be possible, but duplicating all child layers + // is not the right approach. + // todo: implement special case of reparenting child layers + return false; +} + +Layer *GroupLayer::mergedWith(Layer *) const +{ + return nullptr; +} + +Layer *GroupLayer::clone() const +{ + return initializeClone(new GroupLayer(mName, mX, mY)); +} + +GroupLayer *GroupLayer::initializeClone(GroupLayer *clone) const +{ + Layer::initializeClone(clone); + for (const Layer *layer : mLayers) + clone->addLayer(layer->clone()); + return clone; +} + +} // namespace Tiled diff --git a/src/libtiled/grouplayer.h b/src/libtiled/grouplayer.h new file mode 100644 index 0000000000..d9ff73a932 --- /dev/null +++ b/src/libtiled/grouplayer.h @@ -0,0 +1,81 @@ +/* + * grouplayer.h + * Copyright 2017, Thorbjørn Lindeijer + * + * This file is part of Tiled. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef GROUPLAYER_H +#define GROUPLAYER_H + +#include "layer.h" + +#include + +namespace Tiled { + +class TILEDSHARED_EXPORT GroupLayer : public Layer +{ +public: + GroupLayer(const QString &name, int x, int y); + ~GroupLayer(); + + int layerCount() const; + Layer *layerAt(int index) const; + const QList &layers() const { return mLayers; } + + void addLayer(Layer *layer); + void insertLayer(int index, Layer *layer); + Layer *takeLayerAt(int index); + + void setMap(Map *map) override; + bool isEmpty() const override; + QSet usedTilesets() const override; + bool referencesTileset(const Tileset *tileset) const override; + void replaceReferencesToTileset(Tileset *oldTileset, Tileset *newTileset) override; + bool canMergeWith(Layer *other) const override; + Layer *mergedWith(Layer *other) const override; + Layer *clone() const override; + + // Enable easy iteration over children with range-based for + QList::iterator begin() { return mLayers.begin(); } + QList::iterator end() { return mLayers.end(); } + QList::const_iterator begin() const { return mLayers.begin(); } + QList::const_iterator end() const { return mLayers.end(); } + +protected: + GroupLayer *initializeClone(GroupLayer *clone) const; + +private: + void adoptLayer(Layer *layer); + + QList mLayers; +}; + + +inline int GroupLayer::layerCount() const +{ + return mLayers.size(); +} + +inline Layer *GroupLayer::layerAt(int index) const +{ + return mLayers.at(index); +} + +} // namespace Tiled + +#endif // GROUPLAYER_H diff --git a/src/libtiled/layer.h b/src/libtiled/layer.h index 35ab37097d..99bbbcc854 100644 --- a/src/libtiled/layer.h +++ b/src/libtiled/layer.h @@ -55,7 +55,8 @@ class TILEDSHARED_EXPORT Layer : public Object enum TypeFlag { TileLayerType = 0x01, ObjectGroupType = 0x02, - ImageLayerType = 0x04 + ImageLayerType = 0x04, + GroupLayerType = 0x08 }; enum { AnyLayerType = 0xFF }; @@ -109,7 +110,7 @@ class TILEDSHARED_EXPORT Layer : public Object * Sets the map this layer is part of. Should only be called from the * Map class. */ - void setMap(Map *map) { mMap = map; } + virtual void setMap(Map *map) { mMap = map; } /** * Returns the x position of this layer (in tiles). diff --git a/src/libtiled/libtiled.pro b/src/libtiled/libtiled.pro index f7832aa63f..86591bb880 100644 --- a/src/libtiled/libtiled.pro +++ b/src/libtiled/libtiled.pro @@ -30,6 +30,7 @@ contains(QT_CONFIG, reduce_exports): CONFIG += hide_symbols SOURCES += compression.cpp \ filesystemwatcher.cpp \ gidmapper.cpp \ + grouplayer.cpp \ hexagonalrenderer.cpp \ imagelayer.cpp \ imagereference.cpp \ @@ -58,6 +59,7 @@ SOURCES += compression.cpp \ HEADERS += compression.h \ filesystemwatcher.h \ gidmapper.h \ + grouplayer.h \ hexagonalrenderer.h \ imagelayer.h \ imagereference.h \ diff --git a/src/libtiled/libtiled.qbs b/src/libtiled/libtiled.qbs index 6a3088f5e3..0eeee99cc4 100644 --- a/src/libtiled/libtiled.qbs +++ b/src/libtiled/libtiled.qbs @@ -40,6 +40,8 @@ DynamicLibrary { "filesystemwatcher.h", "gidmapper.cpp", "gidmapper.h", + "grouplayer.cpp", + "grouplayer.h", "hexagonalrenderer.cpp", "hexagonalrenderer.h", "imagelayer.cpp", diff --git a/src/libtiled/map.cpp b/src/libtiled/map.cpp index 7ee8bbd98c..204738aa70 100644 --- a/src/libtiled/map.cpp +++ b/src/libtiled/map.cpp @@ -220,12 +220,8 @@ void Map::adoptLayer(Layer *layer) { layer->setMap(this); - if (ObjectGroup *group = layer->asObjectGroup()) { - for (MapObject *o : group->objects()) { - if (o->id() == 0) - o->setId(takeNextObjectId()); - } - } + if (ObjectGroup *group = layer->asObjectGroup()) + initializeObjectIds(*group); } Layer *Map::takeLayerAt(int index) @@ -298,6 +294,14 @@ bool Map::isTilesetUsed(const Tileset *tileset) const return false; } +void Map::initializeObjectIds(ObjectGroup &objectGroup) +{ + for (MapObject *o : objectGroup) { + if (o->id() == 0) + o->setId(takeNextObjectId()); + } +} + QString Tiled::staggerAxisToString(Map::StaggerAxis staggerAxis) { diff --git a/src/libtiled/map.h b/src/libtiled/map.h index a31780a4b4..a375e7cd48 100644 --- a/src/libtiled/map.h +++ b/src/libtiled/map.h @@ -237,6 +237,9 @@ class TILEDSHARED_EXPORT Map : public Object int imageLayerCount() const { return layerCount(Layer::ImageLayerType); } + int groupLayerCount() const + { return layerCount(Layer::GroupLayerType); } + /** * Returns the layer at the specified index. */ @@ -364,6 +367,7 @@ class TILEDSHARED_EXPORT Map : public Object void setNextObjectId(int nextId); int nextObjectId() const; int takeNextObjectId(); + void initializeObjectIds(ObjectGroup &objectGroup); private: void adoptLayer(Layer *layer); diff --git a/src/libtiled/maptovariantconverter.cpp b/src/libtiled/maptovariantconverter.cpp index 9393d93490..d32b23d1fb 100644 --- a/src/libtiled/maptovariantconverter.cpp +++ b/src/libtiled/maptovariantconverter.cpp @@ -21,6 +21,7 @@ #include "maptovariantconverter.h" +#include "grouplayer.h" #include "imagelayer.h" #include "map.h" #include "mapobject.h" @@ -95,6 +96,8 @@ QVariant MapToVariantConverter::toVariant(const Map *map, const QDir &mapDir) case Layer::ImageLayerType: layerVariants << toVariant(static_cast(layer)); break; + case Layer::GroupLayerType: + layerVariants << toVariant(static_cast(layer)); } } mapVariant[QLatin1String("layers")] = layerVariants; @@ -395,6 +398,17 @@ QVariant MapToVariantConverter::toVariant(const ImageLayer *imageLayer) const return imageLayerVariant; } +QVariant MapToVariantConverter::toVariant(const GroupLayer *groupLayer) const +{ + QVariantMap groupLayerVariant; + + addLayerAttributes(groupLayerVariant, groupLayer); + + // todo + + return groupLayerVariant; +} + void MapToVariantConverter::addLayerAttributes(QVariantMap &layerVariant, const Layer *layer) const { diff --git a/src/libtiled/maptovariantconverter.h b/src/libtiled/maptovariantconverter.h index c03ce6677f..dda67264f9 100644 --- a/src/libtiled/maptovariantconverter.h +++ b/src/libtiled/maptovariantconverter.h @@ -29,6 +29,8 @@ namespace Tiled { +class GroupLayer; + /** * Converts Map instances to QVariant. Meant to be used together with * JsonWriter. @@ -58,6 +60,7 @@ class TILEDSHARED_EXPORT MapToVariantConverter Map::LayerDataFormat format) const; QVariant toVariant(const ObjectGroup *objectGroup) const; QVariant toVariant(const ImageLayer *imageLayer) const; + QVariant toVariant(const GroupLayer *groupLayer) const; void addLayerAttributes(QVariantMap &layerVariant, const Layer *layer) const; diff --git a/src/plugins/gmx/gmxplugin.cpp b/src/plugins/gmx/gmxplugin.cpp index 6dfd3950ad..94545fc207 100644 --- a/src/plugins/gmx/gmxplugin.cpp +++ b/src/plugins/gmx/gmxplugin.cpp @@ -298,6 +298,14 @@ bool GmxPlugin::write(const Map *map, const QString &fileName) } break; } + + case Layer::ImageLayerType: + // todo: maybe export as backgrounds? + break; + + case Layer::GroupLayerType: + // todo: recursively export group layers + break; } currentLayer--; diff --git a/src/plugins/lua/luaplugin.cpp b/src/plugins/lua/luaplugin.cpp index 59e652d83d..930b2e2a86 100644 --- a/src/plugins/lua/luaplugin.cpp +++ b/src/plugins/lua/luaplugin.cpp @@ -22,6 +22,7 @@ #include "luatablewriter.h" +#include "grouplayer.h" #include "imagelayer.h" #include "mapobject.h" #include "objectgroup.h" @@ -166,6 +167,9 @@ void LuaPlugin::writeMap(LuaTableWriter &writer, const Map *map) case Layer::ImageLayerType: writeImageLayer(writer, static_cast(layer)); break; + case Layer::GroupLayerType: + writeGroupLayer(writer, static_cast(layer)); + break; } } writer.writeEndTable(); @@ -447,6 +451,11 @@ void LuaPlugin::writeImageLayer(LuaTableWriter &writer, writer.writeEndTable(); } +void LuaPlugin::writeGroupLayer(LuaTableWriter &, const GroupLayer *) +{ + // todo +} + static const char *toString(MapObject::Shape shape) { switch (shape) { diff --git a/src/plugins/lua/luaplugin.h b/src/plugins/lua/luaplugin.h index ec7328e9e9..63c7881621 100644 --- a/src/plugins/lua/luaplugin.h +++ b/src/plugins/lua/luaplugin.h @@ -31,6 +31,7 @@ #include namespace Tiled { +class GroupLayer; class MapObject; class ObjectGroup; class Properties; @@ -66,6 +67,7 @@ class LUASHARED_EXPORT LuaPlugin : public Tiled::WritableMapFormat void writeObjectGroup(LuaTableWriter &, const Tiled::ObjectGroup *, const QByteArray &key = QByteArray()); void writeImageLayer(LuaTableWriter &, const Tiled::ImageLayer *); + void writeGroupLayer(LuaTableWriter &, const Tiled::GroupLayer *); void writeMapObject(LuaTableWriter &, const Tiled::MapObject *); QString mError; diff --git a/src/tiled/adjusttileindexes.cpp b/src/tiled/adjusttileindexes.cpp index 35cb696a6a..f326446864 100644 --- a/src/tiled/adjusttileindexes.cpp +++ b/src/tiled/adjusttileindexes.cpp @@ -118,6 +118,10 @@ AdjustTileIndexes::AdjustTileIndexes(MapDocument *mapDocument, case Layer::ImageLayerType: break; + + case Layer::GroupLayerType: + // todo: recursive + break; } } diff --git a/src/tiled/exportasimagedialog.cpp b/src/tiled/exportasimagedialog.cpp index c4dd5c3d0e..706f5abb7f 100644 --- a/src/tiled/exportasimagedialog.cpp +++ b/src/tiled/exportasimagedialog.cpp @@ -262,6 +262,10 @@ void ExportAsImageDialog::accept() renderer->drawImageLayer(&painter, imageLayer); break; } + + case Layer::GroupLayerType: + // todo: recursive + break; } painter.translate(-layer->offset()); diff --git a/src/tiled/grouplayeritem.cpp b/src/tiled/grouplayeritem.cpp new file mode 100644 index 0000000000..041d7cf907 --- /dev/null +++ b/src/tiled/grouplayeritem.cpp @@ -0,0 +1,50 @@ +/* + * grouplayeritem.cpp + * Copyright 2017, Thorbjørn Lindeijer + * + * This file is part of Tiled. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "grouplayeritem.h" + +#include "grouplayer.h" + +namespace Tiled { +namespace Internal { + +GroupLayerItem::GroupLayerItem(GroupLayer *groupLayer) + : mGroupLayer(groupLayer) +{ + // Since we don't do any painting, we can spare us the call to paint() + setFlag(QGraphicsItem::ItemHasNoContents); + + setOpacity(groupLayer->opacity()); + setPos(groupLayer->offset()); +} + +QRectF GroupLayerItem::boundingRect() const +{ + return QRectF(); +} + +void GroupLayerItem::paint(QPainter *, + const QStyleOptionGraphicsItem *, + QWidget *) +{ +} + +} // namespace Internal +} // namespace Tiled diff --git a/src/tiled/grouplayeritem.h b/src/tiled/grouplayeritem.h new file mode 100644 index 0000000000..2a348ba0c9 --- /dev/null +++ b/src/tiled/grouplayeritem.h @@ -0,0 +1,52 @@ +/* + * grouplayeritem.h + * Copyright 2017, Thorbjørn Lindeijer + * + * This file is part of Tiled. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef GROUPLAYERITEM_H +#define GROUPLAYERITEM_H + +#include + +namespace Tiled { + +class GroupLayer; + +namespace Internal { + +class GroupLayerItem : public QGraphicsItem +{ +public: + GroupLayerItem(GroupLayer *groupLayer); + + GroupLayer *groupLayer() const { return mGroupLayer; } + + // QGraphicsItem + QRectF boundingRect() const override; + void paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget = nullptr) override; + +private: + GroupLayer *mGroupLayer; +}; + +} // namespace Internal +} // namespace Tiled + +#endif // GROUPLAYERITEM_H diff --git a/src/tiled/layermodel.cpp b/src/tiled/layermodel.cpp index 7d1aaccae1..ca1d43af9a 100644 --- a/src/tiled/layermodel.cpp +++ b/src/tiled/layermodel.cpp @@ -37,6 +37,7 @@ LayerModel::LayerModel(QObject *parent): mTileLayerIcon(QLatin1String(":/images/16x16/layer-tile.png")), mObjectGroupIcon(QLatin1String(":/images/16x16/layer-object.png")), mImageLayerIcon(QLatin1String(":/images/16x16/layer-image.png")) + // todo: add mGroupLayerIcon (folder?) { mTileLayerIcon.addFile(QLatin1String(":images/32x32/layer-tile.png")); mObjectGroupIcon.addFile(QLatin1String(":images/32x32/layer-object.png")); @@ -73,6 +74,8 @@ QVariant LayerModel::data(const QModelIndex &index, int role) const return mObjectGroupIcon; case Layer::ImageLayerType: return mImageLayerIcon; + case Layer::GroupLayerType: + return mGroupLayerIcon; } case Qt::CheckStateRole: return layer->isVisible() ? Qt::Checked : Qt::Unchecked; diff --git a/src/tiled/layermodel.h b/src/tiled/layermodel.h index 50fde68a93..3fe7a894b7 100644 --- a/src/tiled/layermodel.h +++ b/src/tiled/layermodel.h @@ -94,6 +94,7 @@ class LayerModel : public QAbstractListModel QIcon mTileLayerIcon; QIcon mObjectGroupIcon; QIcon mImageLayerIcon; + QIcon mGroupLayerIcon; }; /** diff --git a/src/tiled/mapdocument.cpp b/src/tiled/mapdocument.cpp index ad65bd16b6..acc1cd9238 100644 --- a/src/tiled/mapdocument.cpp +++ b/src/tiled/mapdocument.cpp @@ -30,6 +30,7 @@ #include "changeselectedarea.h" #include "containerhelpers.h" #include "documentmanager.h" +#include "grouplayer.h" #include "flipmapobjects.h" #include "hexagonalrenderer.h" #include "imagelayer.h" @@ -321,7 +322,7 @@ void MapDocument::resizeMap(const QSize &size, const QPoint &offset, bool remove } break; } - case Layer::ImageLayerType: + case Layer::ImageLayerType: { // Adjust image layer by changing its offset auto imageLayer = static_cast(layer); new SetLayerOffset(this, layerIndex, @@ -329,6 +330,11 @@ void MapDocument::resizeMap(const QSize &size, const QPoint &offset, bool remove command); break; } + case Layer::GroupLayerType: { + // todo: recursively resize layers in this group + break; + } + } } new ResizeMap(this, size, command); @@ -426,6 +432,10 @@ Layer *MapDocument::addLayer(Layer::TypeFlag layerType) name = tr("Image Layer %1").arg(mMap->imageLayerCount() + 1); layer = new ImageLayer(name, 0, 0); break; + case Layer::GroupLayerType: + name = tr("Group %1").arg(mMap->groupLayerCount() + 1); + layer = new GroupLayer(name, 0, 0); + break; } Q_ASSERT(layer); diff --git a/src/tiled/mapdocumentactionhandler.cpp b/src/tiled/mapdocumentactionhandler.cpp index d32eae0493..6684248cc2 100644 --- a/src/tiled/mapdocumentactionhandler.cpp +++ b/src/tiled/mapdocumentactionhandler.cpp @@ -77,6 +77,7 @@ MapDocumentActionHandler::MapDocumentActionHandler(QObject *parent) mActionAddObjectGroup->setIcon(addObjectLayerIcon); mActionAddImageLayer = new QAction(this); mActionAddImageLayer->setIcon(addImageLayerIcon); + mActionAddGroupLayer = new QAction(this); mActionDuplicateLayer = new QAction(this); mActionDuplicateLayer->setShortcut(tr("Ctrl+Shift+D")); @@ -141,6 +142,7 @@ MapDocumentActionHandler::MapDocumentActionHandler(QObject *parent) connect(mActionAddObjectGroup, SIGNAL(triggered()), SLOT(addObjectGroup())); connect(mActionAddImageLayer, SIGNAL(triggered()), SLOT(addImageLayer())); + connect(mActionAddGroupLayer, SIGNAL(triggered()), SLOT(addGroupLayer())); connect(mActionLayerViaCopy, &QAction::triggered, this, &MapDocumentActionHandler::layerViaCopy); connect(mActionLayerViaCut, &QAction::triggered, this, &MapDocumentActionHandler::layerViaCut); connect(mActionDuplicateLayer, SIGNAL(triggered()), @@ -180,6 +182,7 @@ void MapDocumentActionHandler::retranslateUi() mActionAddTileLayer->setText(tr("&Tile Layer")); mActionAddObjectGroup->setText(tr("&Object Layer")); mActionAddImageLayer->setText(tr("&Image Layer")); + mActionAddGroupLayer->setText(tr("&Group Layer")); mActionLayerViaCopy->setText(tr("Layer via Copy")); mActionLayerViaCut->setText(tr("Layer via Cut")); mActionDuplicateLayer->setText(tr("&Duplicate Layer")); @@ -231,6 +234,7 @@ QMenu *MapDocumentActionHandler::createNewLayerMenu(QWidget *parent) const newLayerMenu->addAction(actionAddTileLayer()); newLayerMenu->addAction(actionAddObjectGroup()); newLayerMenu->addAction(actionAddImageLayer()); + newLayerMenu->addAction(actionAddGroupLayer()); newLayerMenu->addSeparator(); newLayerMenu->addAction(actionLayerViaCopy()); newLayerMenu->addAction(actionLayerViaCut()); @@ -421,6 +425,12 @@ void MapDocumentActionHandler::addImageLayer() mMapDocument->addLayer(Layer::ImageLayerType); } +void MapDocumentActionHandler::addGroupLayer() +{ + if (mMapDocument) + mMapDocument->addLayer(Layer::GroupLayerType); +} + void MapDocumentActionHandler::layerVia(MapDocumentActionHandler::LayerViaVariant variant) { if (!mMapDocument) diff --git a/src/tiled/mapdocumentactionhandler.h b/src/tiled/mapdocumentactionhandler.h index a0bf25a8ec..584433bc0e 100644 --- a/src/tiled/mapdocumentactionhandler.h +++ b/src/tiled/mapdocumentactionhandler.h @@ -67,6 +67,7 @@ class MapDocumentActionHandler : public QObject QAction *actionAddTileLayer() const { return mActionAddTileLayer; } QAction *actionAddObjectGroup() const { return mActionAddObjectGroup; } QAction *actionAddImageLayer() const { return mActionAddImageLayer; } + QAction *actionAddGroupLayer() const { return mActionAddGroupLayer; } QAction *actionLayerViaCopy() const { return mActionLayerViaCopy; } QAction *actionLayerViaCut() const { return mActionLayerViaCut; } QAction *actionDuplicateLayer() const { return mActionDuplicateLayer; } @@ -105,6 +106,7 @@ public slots: void addTileLayer(); void addObjectGroup(); void addImageLayer(); + void addGroupLayer(); void layerViaCopy() { layerVia(ViaCopy); } void layerViaCut() { layerVia(ViaCut); } void layerVia(LayerViaVariant variant); @@ -137,6 +139,7 @@ private slots: QAction *mActionAddTileLayer; QAction *mActionAddObjectGroup; QAction *mActionAddImageLayer; + QAction *mActionAddGroupLayer; QAction *mActionLayerViaCopy; QAction *mActionLayerViaCut; QAction *mActionDuplicateLayer; diff --git a/src/tiled/mapscene.cpp b/src/tiled/mapscene.cpp index dc793e9f2f..1fa170099c 100644 --- a/src/tiled/mapscene.cpp +++ b/src/tiled/mapscene.cpp @@ -25,6 +25,8 @@ #include "abstracttool.h" #include "containerhelpers.h" +#include "grouplayer.h" +#include "grouplayeritem.h" #include "map.h" #include "mapdocument.h" #include "mapobject.h" @@ -235,9 +237,13 @@ QGraphicsItem *MapScene::createLayerItem(Layer *layer) { QGraphicsItem *layerItem = nullptr; - if (TileLayer *tl = layer->asTileLayer()) { - layerItem = new TileLayerItem(tl, mMapDocument); - } else if (ObjectGroup *og = layer->asObjectGroup()) { + switch (layer->layerType()) { + case Layer::TileLayerType: + layerItem = new TileLayerItem(static_cast(layer), mMapDocument); + break; + + case Layer::ObjectGroupType: { + auto og = static_cast(layer); const ObjectGroup::DrawOrder drawOrder = og->drawOrder(); ObjectGroupItem *ogItem = new ObjectGroupItem(og); int objectIndex = 0; @@ -253,8 +259,17 @@ QGraphicsItem *MapScene::createLayerItem(Layer *layer) ++objectIndex; } layerItem = ogItem; - } else if (ImageLayer *il = layer->asImageLayer()) { - layerItem = new ImageLayerItem(il, mMapDocument); + break; + } + + case Layer::ImageLayerType: + layerItem = new ImageLayerItem(static_cast(layer), mMapDocument); + break; + + case Layer::GroupLayerType: + // todo: process child layers + layerItem = new GroupLayerItem(static_cast(layer)); + break; } Q_ASSERT(layerItem); diff --git a/src/tiled/offsetlayer.cpp b/src/tiled/offsetlayer.cpp index 28ab82c52b..c94db4bf10 100644 --- a/src/tiled/offsetlayer.cpp +++ b/src/tiled/offsetlayer.cpp @@ -70,6 +70,10 @@ OffsetLayer::OffsetLayer(MapDocument *mapDocument, } break; } + case Layer::GroupLayerType: { + // todo: apply the offset to each layer in the group? + break; + } } } diff --git a/src/tiled/propertybrowser.cpp b/src/tiled/propertybrowser.cpp index 1912f9c080..1e80d0672e 100644 --- a/src/tiled/propertybrowser.cpp +++ b/src/tiled/propertybrowser.cpp @@ -562,14 +562,15 @@ void PropertyBrowser::addLayerProperties(QtProperty *parent) opacityProperty->setAttribute(QLatin1String("minimum"), 0.0); opacityProperty->setAttribute(QLatin1String("maximum"), 1.0); opacityProperty->setAttribute(QLatin1String("singleStep"), 0.1); + + addProperty(OffsetXProperty, QVariant::Double, tr("Horizontal Offset"), parent); + addProperty(OffsetYProperty, QVariant::Double, tr("Vertical Offset"), parent); } void PropertyBrowser::addTileLayerProperties() { QtProperty *groupProperty = mGroupManager->addProperty(tr("Tile Layer")); addLayerProperties(groupProperty); - addProperty(OffsetXProperty, QVariant::Double, tr("Horizontal Offset"), groupProperty); - addProperty(OffsetYProperty, QVariant::Double, tr("Vertical Offset"), groupProperty); addProperty(groupProperty); } @@ -577,8 +578,6 @@ void PropertyBrowser::addObjectGroupProperties() { QtProperty *groupProperty = mGroupManager->addProperty(tr("Object Layer")); addLayerProperties(groupProperty); - addProperty(OffsetXProperty, QVariant::Double, tr("Horizontal Offset"), groupProperty); - addProperty(OffsetYProperty, QVariant::Double, tr("Vertical Offset"), groupProperty); addProperty(ColorProperty, QVariant::Color, tr("Color"), groupProperty); @@ -606,8 +605,14 @@ void PropertyBrowser::addImageLayerProperties() Utils::readableImageFormatsFilter()); addProperty(ColorProperty, QVariant::Color, tr("Transparent Color"), groupProperty); - addProperty(OffsetXProperty, QVariant::Double, tr("Horizontal Offset"), groupProperty); - addProperty(OffsetYProperty, QVariant::Double, tr("Vertical Offset"), groupProperty); + + addProperty(groupProperty); +} + +void PropertyBrowser::addGroupLayerProperties() +{ + QtProperty *groupProperty = mGroupManager->addProperty(tr("Group Layer")); + addLayerProperties(groupProperty); addProperty(groupProperty); } @@ -896,6 +901,7 @@ void PropertyBrowser::applyLayerValue(PropertyId id, const QVariant &val) case Layer::TileLayerType: applyTileLayerValue(id, val); break; case Layer::ObjectGroupType: applyObjectGroupValue(id, val); break; case Layer::ImageLayerType: applyImageLayerValue(id, val); break; + case Layer::GroupLayerType: applyGroupLayerValue(id, val); break; } break; } @@ -969,7 +975,13 @@ void PropertyBrowser::applyImageLayerValue(PropertyId id, const QVariant &val) } } -void PropertyBrowser::applyTilesetValue(PropertyBrowser::PropertyId id, const QVariant &val) +void PropertyBrowser::applyGroupLayerValue(PropertyId id, const QVariant &val) +{ + Q_UNUSED(id) + Q_UNUSED(val) +} + +void PropertyBrowser::applyTilesetValue(PropertyId id, const QVariant &val) { Tileset *tileset = static_cast(mObject); QUndoStack *undoStack = mDocument->undoStack(); @@ -1140,6 +1152,7 @@ void PropertyBrowser::addProperties() case Layer::TileLayerType: addTileLayerProperties(); break; case Layer::ObjectGroupType: addObjectGroupProperties(); break; case Layer::ImageLayerType: addImageLayerProperties(); break; + case Layer::GroupLayerType: addGroupLayerProperties(); break; } break; case Object::TilesetType: addTilesetProperties(); break; @@ -1236,12 +1249,15 @@ void PropertyBrowser::updateProperties() mIdToProperty[DrawOrderProperty]->setValue(objectGroup->drawOrder()); break; } - case Layer::ImageLayerType: + case Layer::ImageLayerType: { const ImageLayer *imageLayer = static_cast(layer); mIdToProperty[ImageSourceProperty]->setValue(QVariant::fromValue(FilePath { imageLayer->imageSource() })); mIdToProperty[ColorProperty]->setValue(imageLayer->transparentColor()); break; } + case Layer::GroupLayerType: + break; + } break; } case Object::TilesetType: { diff --git a/src/tiled/propertybrowser.h b/src/tiled/propertybrowser.h index 8af77effd3..00647bf5c3 100644 --- a/src/tiled/propertybrowser.h +++ b/src/tiled/propertybrowser.h @@ -154,6 +154,7 @@ private slots: void addTileLayerProperties(); void addObjectGroupProperties(); void addImageLayerProperties(); + void addGroupLayerProperties(); void addTilesetProperties(); void addTileProperties(); void addTerrainProperties(); @@ -165,6 +166,7 @@ private slots: void applyTileLayerValue(PropertyId id, const QVariant &val); void applyObjectGroupValue(PropertyId id, const QVariant &val); void applyImageLayerValue(PropertyId id, const QVariant &val); + void applyGroupLayerValue(PropertyId id, const QVariant &val); void applyTilesetValue(PropertyId id, const QVariant &val); void applyTileValue(PropertyId id, const QVariant &val); void applyTerrainValue(PropertyId id, const QVariant &val); diff --git a/src/tiled/thumbnailrenderer.cpp b/src/tiled/thumbnailrenderer.cpp index 6b31b7783b..143ce0b13c 100644 --- a/src/tiled/thumbnailrenderer.cpp +++ b/src/tiled/thumbnailrenderer.cpp @@ -205,6 +205,10 @@ QImage ThumbnailRenderer::render(const QSize &size) const mRenderer->drawImageLayer(&painter, imageLayer); break; } + case Layer::GroupLayerType: { + // todo: recursively render the layers within this group + break; + } } painter.translate(-layer->offset()); diff --git a/src/tiled/tiled.pro b/src/tiled/tiled.pro index ad77aff089..3b358cb7ff 100644 --- a/src/tiled/tiled.pro +++ b/src/tiled/tiled.pro @@ -134,6 +134,7 @@ SOURCES += aboutdialog.cpp \ flexiblescrollbar.cpp \ flipmapobjects.cpp \ geometry.cpp \ + grouplayeritem.cpp \ id.cpp \ imagecolorpickerwidget.cpp \ imagelayeritem.cpp \ @@ -294,6 +295,7 @@ HEADERS += aboutdialog.h \ flexiblescrollbar.h \ flipmapobjects.h \ geometry.h \ + grouplayeritem.h \ id.h \ imagecolorpickerwidget.h \ imagelayeritem.h \ diff --git a/src/tiled/tiled.qbs b/src/tiled/tiled.qbs index a82de21a51..08b6a7bf19 100644 --- a/src/tiled/tiled.qbs +++ b/src/tiled/tiled.qbs @@ -187,6 +187,8 @@ QtGuiApplication { "flipmapobjects.h", "geometry.cpp", "geometry.h", + "grouplayeritem.cpp", + "grouplayeritem.h", "id.cpp", "id.h", "imagecolorpickerwidget.cpp",