Skip to content

Commit

Permalink
Added GroupLayer and GroupLayerItem
Browse files Browse the repository at this point in the history
A GroupLayer is a new kind of layer that can contain other layers. It is
meant for organizing layers in folders in case you are working with maps
that have a large amount of layers.

The visibility, opacity and later also locked status of the group layer
will affect all child layers. Also the Layers view will allow collapsing
group layers.

This change is only the start. The addition of group layers is expected
to affect a large amount of code.
  • Loading branch information
bjorn committed Jan 17, 2017
1 parent f32e836 commit 5500c56
Show file tree
Hide file tree
Showing 28 changed files with 464 additions and 22 deletions.
130 changes: 130 additions & 0 deletions src/libtiled/grouplayer.cpp
@@ -0,0 +1,130 @@
/*
* grouplayer.cpp
* Copyright 2017, Thorbjørn Lindeijer <bjorn@lindeijer.nl>
*
* 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 <http://www.gnu.org/licenses/>.
*/

#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<SharedTileset> GroupLayer::usedTilesets() const
{
QSet<SharedTileset> 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
81 changes: 81 additions & 0 deletions src/libtiled/grouplayer.h
@@ -0,0 +1,81 @@
/*
* grouplayer.h
* Copyright 2017, Thorbjørn Lindeijer <bjorn@lindeijer.nl>
*
* 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 <http://www.gnu.org/licenses/>.
*/

#ifndef GROUPLAYER_H
#define GROUPLAYER_H

#include "layer.h"

#include <QList>

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<Layer*> &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<SharedTileset> 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<Layer*>::iterator begin() { return mLayers.begin(); }
QList<Layer*>::iterator end() { return mLayers.end(); }
QList<Layer*>::const_iterator begin() const { return mLayers.begin(); }
QList<Layer*>::const_iterator end() const { return mLayers.end(); }

protected:
GroupLayer *initializeClone(GroupLayer *clone) const;

private:
void adoptLayer(Layer *layer);

QList<Layer*> 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
5 changes: 3 additions & 2 deletions src/libtiled/layer.h
Expand Up @@ -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 };
Expand Down Expand Up @@ -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).
Expand Down
2 changes: 2 additions & 0 deletions src/libtiled/libtiled.pro
Expand Up @@ -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 \
Expand Down Expand Up @@ -58,6 +59,7 @@ SOURCES += compression.cpp \
HEADERS += compression.h \
filesystemwatcher.h \
gidmapper.h \
grouplayer.h \
hexagonalrenderer.h \
imagelayer.h \
imagereference.h \
Expand Down
2 changes: 2 additions & 0 deletions src/libtiled/libtiled.qbs
Expand Up @@ -40,6 +40,8 @@ DynamicLibrary {
"filesystemwatcher.h",
"gidmapper.cpp",
"gidmapper.h",
"grouplayer.cpp",
"grouplayer.h",
"hexagonalrenderer.cpp",
"hexagonalrenderer.h",
"imagelayer.cpp",
Expand Down
16 changes: 10 additions & 6 deletions src/libtiled/map.cpp
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions src/libtiled/map.h
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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);
Expand Down
14 changes: 14 additions & 0 deletions src/libtiled/maptovariantconverter.cpp
Expand Up @@ -21,6 +21,7 @@

#include "maptovariantconverter.h"

#include "grouplayer.h"
#include "imagelayer.h"
#include "map.h"
#include "mapobject.h"
Expand Down Expand Up @@ -95,6 +96,8 @@ QVariant MapToVariantConverter::toVariant(const Map *map, const QDir &mapDir)
case Layer::ImageLayerType:
layerVariants << toVariant(static_cast<const ImageLayer*>(layer));
break;
case Layer::GroupLayerType:
layerVariants << toVariant(static_cast<const GroupLayer*>(layer));
}
}
mapVariant[QLatin1String("layers")] = layerVariants;
Expand Down Expand Up @@ -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
{
Expand Down
3 changes: 3 additions & 0 deletions src/libtiled/maptovariantconverter.h
Expand Up @@ -29,6 +29,8 @@

namespace Tiled {

class GroupLayer;

/**
* Converts Map instances to QVariant. Meant to be used together with
* JsonWriter.
Expand Down Expand Up @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions src/plugins/gmx/gmxplugin.cpp
Expand Up @@ -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--;
Expand Down

0 comments on commit 5500c56

Please sign in to comment.