Skip to content

Commit

Permalink
Added Swap Tiles action
Browse files Browse the repository at this point in the history
This swaps the usage of the two selected tiles on the current tile
layer. It is only enabled when exactly two tiles are selected.

Change rebased and amended by @bjorn.
  • Loading branch information
theHacker authored and bjorn committed Feb 28, 2017
1 parent 6dc2213 commit 2c6cde6
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 0 deletions.
95 changes: 95 additions & 0 deletions src/tiled/swaptiles.cpp
@@ -0,0 +1,95 @@
/*
* swaptiles.cpp
* Copyright 2015, Alexander "theHacker" Münch <git@thehacker.biz>
*
* 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 "swaptiles.h"

#include "mapdocument.h"
#include "tilelayer.h"
#include "tileset.h"

#include <QCoreApplication>

#include <limits.h>

namespace Tiled {
namespace Internal {

SwapTiles::SwapTiles(MapDocument *mapDocument,
TileLayer *tileLayer,
Tile *tile1,
Tile *tile2)
: QUndoCommand(QCoreApplication::translate("Undo Commands",
"Swap Tiles"))
, mMapDocument(mapDocument)
, mTileLayer(tileLayer)
, mTile1(tile1)
, mTile2(tile2)
{}

void SwapTiles::swap()
{
// Remember smallest and largest x/y to give emitRegionChanged() the smallest possible rectangle
int minXChanged = INT_MAX;
int minYChanged = INT_MAX;
int maxXChanged = INT_MIN;
int maxYChanged = INT_MIN;

for (int y = 0; y < mTileLayer->height(); y++) {
for (int x = 0; x < mTileLayer->width(); x++) {
bool tileSwapped = false;

const Cell &cell = mTileLayer->cellAt(x, y);
if (cell.tile() == mTile1) {
Cell swapCell = cell;
swapCell.setTile(mTile2);
mTileLayer->setCell(x, y, swapCell);

tileSwapped = true;
} else if (cell.tile() == mTile2) {
Cell swapCell = cell;
swapCell.setTile(mTile1);
mTileLayer->setCell(x, y, swapCell);

tileSwapped = true;
}

if (tileSwapped) {
if (x < minXChanged) minXChanged = x;
if (y < minYChanged) minYChanged = y;
if (x > maxXChanged) maxXChanged = x;
if (y > maxYChanged) maxYChanged = y;
}
}
}

// We changed at least one tile? Call emitRegionChanged() to redraw
if (minXChanged != INT_MAX) {
QRegion regionChanged(
minXChanged,
minYChanged,
maxXChanged - minXChanged + 1,
maxYChanged - minYChanged + 1
);
emit mMapDocument->regionChanged(regionChanged, mTileLayer);
}
}

} // namespace Internal
} // namespace Tiled
73 changes: 73 additions & 0 deletions src/tiled/swaptiles.h
@@ -0,0 +1,73 @@
/*
* swaptiles.h
* Copyright 2015, Alexander "theHacker" Münch <git@thehacker.biz>
*
* 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 SWAPTILES_H
#define SWAPTILES_H

#include "undocommands.h"

#include <QUndoCommand>

namespace Tiled {

class Tile;
class TileLayer;

namespace Internal {

class MapDocument;

/**
* A command that swaps two tiles on a TileLayer
*/
class SwapTiles : public QUndoCommand
{
public:
/**
* Constructor.
*
* @param mapDocument the map document that's being edited
* @param tileLayer the TileLayer to swap the tiles
* @param tile1 the first tile
* @param tile2 the second tile
*/
SwapTiles(MapDocument *mapDocument,
TileLayer *tileLayer,
Tile *tile1,
Tile *tile2);

~SwapTiles() {}

void undo() { swap(); }
void redo() { swap(); }

private:
void swap();

MapDocument *mMapDocument;
TileLayer *mTileLayer;
Tile *mTile1;
Tile *mTile2;
};

} // namespace Internal
} // namespace Tiled

#endif // SWAPTILES_H
2 changes: 2 additions & 0 deletions src/tiled/tiled.pro
Expand Up @@ -202,6 +202,7 @@ SOURCES += aboutdialog.cpp \
stampbrush.cpp \
standardautoupdater.cpp \
stylehelper.cpp \
swaptiles.cpp \
terrainbrush.cpp \
terraindock.cpp \
terrainmodel.cpp \
Expand Down Expand Up @@ -371,6 +372,7 @@ HEADERS += aboutdialog.h \
stampbrush.h \
standardautoupdater.h \
stylehelper.h \
swaptiles.h \
terrainbrush.h \
terraindock.h \
terrainmodel.h \
Expand Down
2 changes: 2 additions & 0 deletions src/tiled/tiled.qbs
Expand Up @@ -330,6 +330,8 @@ QtGuiApplication {
"standardautoupdater.h",
"stylehelper.cpp",
"stylehelper.h",
"swaptiles.cpp",
"swaptiles.h",
"terrainbrush.cpp",
"terrainbrush.h",
"terraindock.cpp",
Expand Down
17 changes: 17 additions & 0 deletions src/tiled/tilesetdock.cpp
Expand Up @@ -34,6 +34,7 @@
#include "objectgroup.h"
#include "preferences.h"
#include "replacetileset.h"
#include "swaptiles.h"
#include "terrain.h"
#include "tile.h"
#include "tilelayer.h"
Expand Down Expand Up @@ -508,6 +509,9 @@ void TilesetDock::createTilesetView(int index, TilesetDocument *tilesetDocument)
this, &TilesetDock::tileImageSourceChanged);
connect(tilesetDocument, &TilesetDocument::tileAnimationChanged,
this, &TilesetDock::tileAnimationChanged);

connect(view, &TilesetView::swapTilesRequested,
this, &TilesetDock::swapTiles);
}

void TilesetDock::deleteTilesetView(int index)
Expand Down Expand Up @@ -923,3 +927,16 @@ void TilesetDock::refreshTilesetMenu()
mTilesetMenuMapper->setMapping(action, i);
}
}

void TilesetDock::swapTiles(Tile *tileA, Tile *tileB)
{
if (!mMapDocument)
return;

TileLayer *tileLayer = dynamic_cast<TileLayer*>(mMapDocument->currentLayer());
if (!tileLayer)
return;

QUndoStack *undoStack = mMapDocument->undoStack();
undoStack->push(new SwapTiles(mMapDocument, tileLayer, tileA, tileB));
}
2 changes: 2 additions & 0 deletions src/tiled/tilesetdock.h
Expand Up @@ -129,6 +129,8 @@ private slots:

void refreshTilesetMenu();

void swapTiles(Tile *tileA, Tile *tileB);

private:
void setCurrentTile(Tile *tile);
void setCurrentTiles(TileLayer *tiles);
Expand Down
27 changes: 27 additions & 0 deletions src/tiled/tilesetview.cpp
Expand Up @@ -698,6 +698,17 @@ void TilesetView::contextMenuEvent(QContextMenuEvent *event)
Utils::setThemeIcon(tileProperties, "document-properties");
connect(tileProperties, SIGNAL(triggered()),
SLOT(editTileProperties()));
} else {
// Assuming we're used in the MapEditor

// Enable "swap" if there are exactly 2 tiles selected
bool exactlyTwoTilesSelected =
(selectionModel()->selectedIndexes().size() == 2);

QAction *swapTilesAction = menu.addAction(tr("&Swap Tiles"));
swapTilesAction->setEnabled(exactlyTwoTilesSelected);
connect(swapTilesAction, SIGNAL(triggered()),
SLOT(swapTiles()));
}

menu.addSeparator();
Expand Down Expand Up @@ -738,6 +749,22 @@ void TilesetView::editTileProperties()
emit mTilesetDocument->editCurrentObject();
}

void TilesetView::swapTiles()
{
const QModelIndexList selectedIndexes = selectionModel()->selectedIndexes();
if (selectedIndexes.size() != 2)
return;

const TilesetModel *model = tilesetModel();
Tile *tile1 = model->tileAt(selectedIndexes[0]);
Tile *tile2 = model->tileAt(selectedIndexes[1]);

if (!tile1 || !tile2)
return;

emit swapTilesRequested(tile1, tile2);
}

void TilesetView::setDrawGrid(bool drawGrid)
{
mDrawGrid = drawGrid;
Expand Down
2 changes: 2 additions & 0 deletions src/tiled/tilesetview.h
Expand Up @@ -116,6 +116,7 @@ class TilesetView : public QTableView
signals:
void createNewTerrain(Tile *tile);
void terrainImageSelected(Tile *tile);
void swapTilesRequested(Tile *tileA, Tile *tileB);

protected:
bool event(QEvent *event) override;
Expand All @@ -130,6 +131,7 @@ private slots:
void addTerrainType();
void selectTerrainImage();
void editTileProperties();
void swapTiles();
void setDrawGrid(bool drawGrid);

void adjustScale();
Expand Down
10 changes: 10 additions & 0 deletions translations/tiled_de.ts
Expand Up @@ -4391,6 +4391,11 @@ Bitte Format angeben.</translation>
</message>
<message>
<location line="+16"/>
<source>&amp;Swap Tiles</source>
<translation>Kacheln ver&amp;tauschen</translation>
</message>
<message>
<location line="+9"/>
<source>Show &amp;Grid</source>
<translation>&amp;Raster anzeigen</translation>
</message>
Expand Down Expand Up @@ -4789,6 +4794,11 @@ Bitte Format angeben.</translation>
<source>Change Layer Data Format</source>
<translation>Ebenen-Datenformat ändern</translation>
</message>
<message>
<location filename="../src/tiled/swaptiles.cpp" line="+35"/>
<source>Swap Tiles</source>
<translation>Kacheln vertauschen</translation>
</message>
<message>
<location filename="../src/tiled/changetileprobability.cpp" line="+41"/>
<location line="+14"/>
Expand Down

0 comments on commit 2c6cde6

Please sign in to comment.