Skip to content

Commit

Permalink
Enable multi-layer editing in the Stamp Brush
Browse files Browse the repository at this point in the history
* The Stamp Brush now captures from all selected layers on right-click
  drag, creating a multi-layer stamp.
* In case of a multi-layer stamp, a multi-layer preview brush is built.
* The brush preview can now visualize multiple tile layers.
* The paint operation can now handle multiple layers, including to merge
  the undo commands.
* When painting multiple layers, the target layers are matched by name.
  New layers are created when no layers with the given name exist yet.

While this is good progress, it's still only the start since many other
tools as well as many actions should still be adapted to handle
multiple selected layers.

Issue #282
  • Loading branch information
bjorn committed Dec 19, 2017
1 parent 20716cd commit 0319039
Show file tree
Hide file tree
Showing 21 changed files with 606 additions and 337 deletions.
2 changes: 1 addition & 1 deletion src/libtiled/grouplayer.h
Expand Up @@ -30,7 +30,7 @@ class TILEDSHARED_EXPORT GroupLayer : public Layer
{
public:
GroupLayer(const QString &name, int x, int y);
~GroupLayer();
~GroupLayer() override;

int layerCount() const;
Layer *layerAt(int index) const;
Expand Down
114 changes: 59 additions & 55 deletions src/libtiled/layer.cpp
Expand Up @@ -193,39 +193,41 @@ Layer *LayerIterator::next()
Layer *layer = mCurrentLayer;
int index = mSiblingIndex;

if (!layer) {
// Traverse to the first layer of the map
if (mMap && index == -1 && mMap->layerCount() > 0) {
layer = mMap->layerAt(0);
index = 0;
do {
if (!layer) {
// Traverse to the first layer of the map
if (mMap && index == -1 && mMap->layerCount() > 0) {
layer = mMap->layerAt(0);
index = 0;
} else {
return nullptr;
}
} else {
return nullptr;
// Traverse to next sibling
++index;
}
} else {
// Traverse to next sibling
++index;
}

const auto siblings = layer->siblings();
const auto siblings = layer->siblings();

// Traverse to parent layer if last child
if (index == siblings.size()) {
layer = layer->parentLayer();
index = layer ? layer->siblingIndex() : -1;
} else {
layer = siblings.at(index);

// If next layer is a group, traverse to its first child
while (layer->isGroupLayer()) {
auto groupLayer = static_cast<GroupLayer*>(layer);
if (groupLayer->layerCount() > 0) {
index = 0;
layer = groupLayer->layerAt(0);
} else {
break;
// Traverse to parent layer if last child
if (index == siblings.size()) {
layer = layer->parentLayer();
index = layer ? layer->siblingIndex() : -1;
} else {
layer = siblings.at(index);

// If next layer is a group, traverse to its first child
while (layer->isGroupLayer()) {
auto groupLayer = static_cast<GroupLayer*>(layer);
if (groupLayer->layerCount() > 0) {
index = 0;
layer = groupLayer->layerAt(0);
} else {
break;
}
}
}
}
} while (layer && !(layer->layerType() & mLayerTypes));

mCurrentLayer = layer;
mSiblingIndex = index;
Expand All @@ -238,37 +240,39 @@ Layer *LayerIterator::previous()
Layer *layer = mCurrentLayer;
int index = mSiblingIndex - 1;

if (!layer) {
// Traverse to the last layer of the map if at the end
if (mMap && index < mMap->layerCount() && mMap->layerCount() > 0) {
layer = mMap->layerAt(index);
} else {
return nullptr;
}
} else {
// Traverse down to last child if applicable
if (layer->isGroupLayer()) {
auto groupLayer = static_cast<GroupLayer*>(layer);
if (groupLayer->layerCount() > 0) {
mSiblingIndex = groupLayer->layerCount() - 1;
mCurrentLayer = groupLayer->layerAt(mSiblingIndex);
return mCurrentLayer;
do {
if (!layer) {
// Traverse to the last layer of the map if at the end
if (mMap && index < mMap->layerCount() && mMap->layerCount() > 0) {
layer = mMap->layerAt(index);
} else {
return nullptr;
}
}

// Traverse to previous sibling (possibly of a parent)
do {
if (index >= 0) {
const auto siblings = layer->siblings();
layer = siblings.at(index);
break;
} else {
// Traverse down to last child if applicable
if (layer->isGroupLayer()) {
auto groupLayer = static_cast<GroupLayer*>(layer);
if (groupLayer->layerCount() > 0) {
mSiblingIndex = groupLayer->layerCount() - 1;
mCurrentLayer = groupLayer->layerAt(mSiblingIndex);
return mCurrentLayer;
}
}

layer = layer->parentLayer();
if (layer)
index = layer->siblingIndex() - 1;
} while (layer);
}
// Traverse to previous sibling (possibly of a parent)
do {
if (index >= 0) {
const auto siblings = layer->siblings();
layer = siblings.at(index);
break;
}

layer = layer->parentLayer();
if (layer)
index = layer->siblingIndex() - 1;
} while (layer);
}
} while (layer && !(layer->layerType() & mLayerTypes));

mCurrentLayer = layer;
mSiblingIndex = index;
Expand Down
7 changes: 5 additions & 2 deletions src/libtiled/layer.h
Expand Up @@ -274,7 +274,7 @@ inline QPointF Layer::offset() const
class TILEDSHARED_EXPORT LayerIterator
{
public:
LayerIterator(const Map *map);
LayerIterator(const Map *map, int layerTypes = Layer::AnyLayerType);
LayerIterator(Layer *start);

Layer *currentLayer() const;
Expand All @@ -294,16 +294,18 @@ class TILEDSHARED_EXPORT LayerIterator
const Map *mMap;
Layer *mCurrentLayer;
int mSiblingIndex;
int mLayerTypes;
};


/**
* Iterate the given map, starting from the first layer.
*/
inline LayerIterator::LayerIterator(const Map *map)
inline LayerIterator::LayerIterator(const Map *map, int layerTypes)
: mMap(map)
, mCurrentLayer(nullptr)
, mSiblingIndex(-1)
, mLayerTypes(layerTypes)
{}

/**
Expand All @@ -313,6 +315,7 @@ inline LayerIterator::LayerIterator(Layer *start)
: mMap(start ? start->map() : nullptr)
, mCurrentLayer(start)
, mSiblingIndex(start ? start->siblingIndex() : -1)
, mLayerTypes(Layer::AnyLayerType)
{}

inline Layer *LayerIterator::currentLayer() const
Expand Down
65 changes: 55 additions & 10 deletions src/libtiled/map.cpp
Expand Up @@ -37,7 +37,7 @@
#include "tilelayer.h"
#include "mapobject.h"

#include <cmath>
#include <QtMath>

using namespace Tiled;

Expand All @@ -60,6 +60,15 @@ Map::Map(Orientation orientation,
{
}

Map::Map(Orientation orientation,
QSize size, QSize tileSize, bool infinite)
: Map(orientation,
size.width(), size.height(),
tileSize.width(), tileSize.height(),
infinite)
{
}

Map::Map(const Map &map):
Object(map),
mOrientation(map.mOrientation),
Expand Down Expand Up @@ -118,10 +127,10 @@ QMargins Map::computeLayerOffsetMargins() const

for (const Layer *layer : mLayers) {
const QPointF offset = layer->offset();
offsetMargins = maxMargins(QMargins(std::ceil(-offset.x()),
std::ceil(-offset.y()),
std::ceil(offset.x()),
std::ceil(offset.y())),
offsetMargins = maxMargins(QMargins(qCeil(-offset.x()),
qCeil(-offset.y()),
qCeil(offset.x()),
qCeil(offset.y())),
offsetMargins);
}

Expand Down Expand Up @@ -171,6 +180,11 @@ int Map::layerCount(Layer::TypeFlag type) const
return count;
}

/**
* Returns the list of all object groups.
*
* @deprecated Use the LayerIterator instead.
*/
QList<ObjectGroup*> Map::objectGroups() const
{
QList<ObjectGroup*> layers;
Expand All @@ -181,6 +195,11 @@ QList<ObjectGroup*> Map::objectGroups() const
return layers;
}

/**
* Returns the list of all tile layers.
*
* @deprecated Use the LayerIterator instead.
*/
QList<TileLayer*> Map::tileLayers() const
{
QList<TileLayer*> layers;
Expand All @@ -197,7 +216,7 @@ void Map::addLayer(Layer *layer)
mLayers.append(layer);
}

int Map::indexOfLayer(const QString &layerName, unsigned layertypes) const
int Map::indexOfLayer(const QString &layerName, int layertypes) const
{
for (int index = 0; index < mLayers.size(); index++)
if (layerAt(index)->name() == layerName
Expand All @@ -207,6 +226,15 @@ int Map::indexOfLayer(const QString &layerName, unsigned layertypes) const
return -1;
}

Layer *Map::findLayer(const QString &name, int layerTypes) const
{
LayerIterator it(this, layerTypes);
while (Layer *layer = it.next())
if (layer->name() == name)
return layer;
return nullptr;
}

void Map::insertLayer(int index, Layer *layer)
{
adoptLayer(layer);
Expand Down Expand Up @@ -282,6 +310,18 @@ bool Map::replaceTileset(const SharedTileset &oldTileset,
}
}

QSet<SharedTileset> Map::usedTilesets() const
{
QSet<SharedTileset> tilesets;

// Only top-level layers need to be considered, since GroupLayer goes over
// its children
for (const Layer *layer : mLayers)
tilesets |= layer->usedTilesets();

return tilesets;
}

bool Map::isTilesetUsed(const Tileset *tileset) const
{
for (const Layer *layer : mLayers)
Expand Down Expand Up @@ -319,10 +359,18 @@ void Map::initializeObjectIds(ObjectGroup &objectGroup)
}
}

QRegion Map::tileRegion() const
{
QRegion region;
LayerIterator it(this, Layer::TileLayerType);
while (auto tileLayer = static_cast<TileLayer*>(it.next()))
region |= tileLayer->region();
return region;
}

QString Tiled::staggerAxisToString(Map::StaggerAxis staggerAxis)
{
switch (staggerAxis) {
default:
case Map::StaggerY:
return QLatin1String("y");
case Map::StaggerX:
Expand All @@ -341,7 +389,6 @@ Map::StaggerAxis Tiled::staggerAxisFromString(const QString &string)
QString Tiled::staggerIndexToString(Map::StaggerIndex staggerIndex)
{
switch (staggerIndex) {
default:
case Map::StaggerOdd:
return QLatin1String("odd");
case Map::StaggerEven:
Expand All @@ -360,7 +407,6 @@ Map::StaggerIndex Tiled::staggerIndexFromString(const QString &string)
QString Tiled::orientationToString(Map::Orientation orientation)
{
switch (orientation) {
default:
case Map::Unknown:
return QLatin1String("unknown");
case Map::Orthogonal:
Expand Down Expand Up @@ -392,7 +438,6 @@ Map::Orientation Tiled::orientationFromString(const QString &string)
QString Tiled::renderOrderToString(Map::RenderOrder renderOrder)
{
switch (renderOrder) {
default:
case Map::RightDown:
return QLatin1String("right-down");
case Map::RightUp:
Expand Down

0 comments on commit 0319039

Please sign in to comment.