From 66c85c24cbb191398350d2c072d944716d84d2e0 Mon Sep 17 00:00:00 2001 From: theHacker Date: Mon, 19 Jan 2015 22:08:48 +0100 Subject: [PATCH 1/4] Two tiles on TileLayer can now be swapped --- src/tiled/tilesetview.cpp | 42 +++++++++++++++++++++++++++++++++++++++ src/tiled/tilesetview.h | 1 + 2 files changed, 43 insertions(+) diff --git a/src/tiled/tilesetview.cpp b/src/tiled/tilesetview.cpp index 161b6f8fa3..3410bdcf4e 100644 --- a/src/tiled/tilesetview.cpp +++ b/src/tiled/tilesetview.cpp @@ -582,6 +582,15 @@ void TilesetView::contextMenuEvent(QContextMenuEvent *event) Utils::setThemeIcon(tileProperties, "document-properties"); connect(tileProperties, SIGNAL(triggered()), SLOT(editTileProperties())); + + // Enable "swap" if there are exactly 2 tiles selected + bool exactlyTwoTilesSelected = + (selectionModel()->selectedIndexes().size() == 2); + + QAction *tileSwap = menu.addAction(tr("Swap tiles")); + tileSwap->setEnabled(exactlyTwoTilesSelected); + connect(tileSwap, SIGNAL(triggered()), + SLOT(swapTiles())); } menu.addSeparator(); @@ -620,6 +629,39 @@ void TilesetView::editTileProperties() mMapDocument->emitEditCurrentObject(); } +void TilesetView::swapTiles() +{ + if (selectionModel()->selectedIndexes().size() != 2) + return; + + TileLayer *tileLayer = dynamic_cast(mMapDocument->currentLayer()); + if (!tileLayer) + return; + + const TilesetModel *model = tilesetModel(); + Tile *tile1 = model->tileAt(selectionModel()->selectedIndexes()[0]); + Tile *tile2 = model->tileAt(selectionModel()->selectedIndexes()[1]); + + for (int y = 0; y < tileLayer->height(); y++) { + for (int x = 0; x < tileLayer->width(); x++) { + const Cell &cell = tileLayer->cellAt(x, y); + + if (cell.tile == tile1) { + Cell swapCell = cell; + swapCell.tile = tile2; + tileLayer->setCell(x, y, swapCell); + } + else if (cell.tile == tile2) { + Cell swapCell = cell; + swapCell.tile = tile1; + tileLayer->setCell(x, y, swapCell); + } + } + } + + // TODO UndoStack +} + void TilesetView::setDrawGrid(bool drawGrid) { mDrawGrid = drawGrid; diff --git a/src/tiled/tilesetview.h b/src/tiled/tilesetview.h index b63024484e..51825250ec 100644 --- a/src/tiled/tilesetview.h +++ b/src/tiled/tilesetview.h @@ -126,6 +126,7 @@ private slots: void createNewTerrain(); void selectTerrainImage(); void editTileProperties(); + void swapTiles(); void setDrawGrid(bool drawGrid); void adjustScale(); From 558e246bef14c2befd8404c923a3651b9f7993c2 Mon Sep 17 00:00:00 2001 From: theHacker Date: Mon, 19 Jan 2015 23:25:19 +0100 Subject: [PATCH 2/4] Implemented QUndoCommand for swapTiles --- src/tiled/swaptiles.cpp | 64 ++++++++++++++++++++++++++++++++++ src/tiled/swaptiles.h | 73 +++++++++++++++++++++++++++++++++++++++ src/tiled/tiled.pro | 1 + src/tiled/tiled.qbs | 2 ++ src/tiled/tilesetview.cpp | 22 +++--------- 5 files changed, 144 insertions(+), 18 deletions(-) create mode 100644 src/tiled/swaptiles.cpp create mode 100644 src/tiled/swaptiles.h diff --git a/src/tiled/swaptiles.cpp b/src/tiled/swaptiles.cpp new file mode 100644 index 0000000000..4be96fbbb6 --- /dev/null +++ b/src/tiled/swaptiles.cpp @@ -0,0 +1,64 @@ +/* + * swaptiles.cpp + * Copyright 2015, Alexander "theHacker" Münch + * + * 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 "swaptiles.h" + +#include "mapdocument.h" +#include "tileset.h" + +#include + +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() +{ + for (int y = 0; y < mTileLayer->height(); y++) { + for (int x = 0; x < mTileLayer->width(); x++) { + const Cell &cell = mTileLayer->cellAt(x, y); + + if (cell.tile == mTile1) { + Cell swapCell = cell; + swapCell.tile = mTile2; + mTileLayer->setCell(x, y, swapCell); + } + else if (cell.tile == mTile2) { + Cell swapCell = cell; + swapCell.tile = mTile1; + mTileLayer->setCell(x, y, swapCell); + } + } + } +} + +} // namespace Internal +} // namespace Tiled diff --git a/src/tiled/swaptiles.h b/src/tiled/swaptiles.h new file mode 100644 index 0000000000..f3ad680cac --- /dev/null +++ b/src/tiled/swaptiles.h @@ -0,0 +1,73 @@ +/* + * swaptiles.h + * Copyright 2015, Alexander "theHacker" Münch + * + * 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 SWAPTILES_H +#define SWAPTILES_H + +#include "undocommands.h" + +#include + +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 diff --git a/src/tiled/tiled.pro b/src/tiled/tiled.pro index 18d6eae0a9..3fa171d7a0 100644 --- a/src/tiled/tiled.pro +++ b/src/tiled/tiled.pro @@ -131,6 +131,7 @@ SOURCES += aboutdialog.cpp \ propertiesdock.cpp \ propertybrowser.cpp \ quickstampmanager.cpp \ + swaptiles.cpp \ raiselowerhelper.cpp \ renamelayer.cpp \ renameterrain.cpp \ diff --git a/src/tiled/tiled.qbs b/src/tiled/tiled.qbs index 0a1b5b25aa..4ad0fe494a 100644 --- a/src/tiled/tiled.qbs +++ b/src/tiled/tiled.qbs @@ -243,6 +243,8 @@ QtGuiApplication { "selectionrectangle.h", "stampbrush.cpp", "stampbrush.h", + "swaptiles.cpp", + "swaptiles.h", "terrainbrush.cpp", "terrainbrush.h", "terraindock.cpp", diff --git a/src/tiled/tilesetview.cpp b/src/tiled/tilesetview.cpp index 3410bdcf4e..cacee8cfbe 100644 --- a/src/tiled/tilesetview.cpp +++ b/src/tiled/tilesetview.cpp @@ -24,6 +24,7 @@ #include "map.h" #include "mapdocument.h" #include "preferences.h" +#include "swaptiles.h" #include "tmxmapwriter.h" #include "tile.h" #include "tileset.h" @@ -642,24 +643,9 @@ void TilesetView::swapTiles() Tile *tile1 = model->tileAt(selectionModel()->selectedIndexes()[0]); Tile *tile2 = model->tileAt(selectionModel()->selectedIndexes()[1]); - for (int y = 0; y < tileLayer->height(); y++) { - for (int x = 0; x < tileLayer->width(); x++) { - const Cell &cell = tileLayer->cellAt(x, y); - - if (cell.tile == tile1) { - Cell swapCell = cell; - swapCell.tile = tile2; - tileLayer->setCell(x, y, swapCell); - } - else if (cell.tile == tile2) { - Cell swapCell = cell; - swapCell.tile = tile1; - tileLayer->setCell(x, y, swapCell); - } - } - } - - // TODO UndoStack + QUndoStack *undoStack = mMapDocument->undoStack(); + QUndoCommand *command = new SwapTiles(mMapDocument, tileLayer, tile1, tile2); + undoStack->push(command); } void TilesetView::setDrawGrid(bool drawGrid) From 6a95701e7a637fda8e35cdca655fd5a1ab050b43 Mon Sep 17 00:00:00 2001 From: theHacker Date: Mon, 19 Jan 2015 23:28:58 +0100 Subject: [PATCH 3/4] Added German translations for swapTiles --- translations/tiled_de.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/translations/tiled_de.ts b/translations/tiled_de.ts index 15fcd4dccd..0d921a8e49 100644 --- a/translations/tiled_de.ts +++ b/translations/tiled_de.ts @@ -3564,6 +3564,11 @@ Do you want to replace it? + Swap tiles + Kacheln ver&tauschen + + + Show &Grid &Raster anzeigen @@ -3949,6 +3954,11 @@ Do you want to replace it? Change Layer Data Format Ebenen-Datenformat ändern + + + Swap Tiles + Kacheln vertauschen + Utils From c06170512b87e8e394c76110a6c0af51c428f6a7 Mon Sep 17 00:00:00 2001 From: theHacker Date: Mon, 23 Feb 2015 22:55:55 +0100 Subject: [PATCH 4/4] Implemented review notes - Swapping tiles triggers emitRegionChanged() for redrawing - "Swap tiles" -> "Swap Tiles". Added mnemonic as well in English. - Refactoring: Extracted variable --- src/tiled/swaptiles.cpp | 33 ++++++++++++++++++++++++++++++++- src/tiled/tilesetview.cpp | 9 +++++---- translations/tiled_de.ts | 2 +- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/tiled/swaptiles.cpp b/src/tiled/swaptiles.cpp index 4be96fbbb6..17cedbcac7 100644 --- a/src/tiled/swaptiles.cpp +++ b/src/tiled/swaptiles.cpp @@ -25,6 +25,8 @@ #include +#include + namespace Tiled { namespace Internal { @@ -42,22 +44,51 @@ SwapTiles::SwapTiles(MapDocument *mapDocument, 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++) { - const Cell &cell = mTileLayer->cellAt(x, y); + bool tileSwapped = false; + const Cell &cell = mTileLayer->cellAt(x, y); if (cell.tile == mTile1) { Cell swapCell = cell; swapCell.tile = mTile2; mTileLayer->setCell(x, y, swapCell); + + tileSwapped = true; } else if (cell.tile == mTile2) { Cell swapCell = cell; swapCell.tile = 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 + ); + mMapDocument->emitRegionChanged(regionChanged); + } } } // namespace Internal diff --git a/src/tiled/tilesetview.cpp b/src/tiled/tilesetview.cpp index cacee8cfbe..5ee030eaa9 100644 --- a/src/tiled/tilesetview.cpp +++ b/src/tiled/tilesetview.cpp @@ -588,7 +588,7 @@ void TilesetView::contextMenuEvent(QContextMenuEvent *event) bool exactlyTwoTilesSelected = (selectionModel()->selectedIndexes().size() == 2); - QAction *tileSwap = menu.addAction(tr("Swap tiles")); + QAction *tileSwap = menu.addAction(tr("&Swap Tiles")); tileSwap->setEnabled(exactlyTwoTilesSelected); connect(tileSwap, SIGNAL(triggered()), SLOT(swapTiles())); @@ -632,7 +632,8 @@ void TilesetView::editTileProperties() void TilesetView::swapTiles() { - if (selectionModel()->selectedIndexes().size() != 2) + const QModelIndexList selectedIndexes = selectionModel()->selectedIndexes(); + if (selectedIndexes.size() != 2) return; TileLayer *tileLayer = dynamic_cast(mMapDocument->currentLayer()); @@ -640,8 +641,8 @@ void TilesetView::swapTiles() return; const TilesetModel *model = tilesetModel(); - Tile *tile1 = model->tileAt(selectionModel()->selectedIndexes()[0]); - Tile *tile2 = model->tileAt(selectionModel()->selectedIndexes()[1]); + Tile *tile1 = model->tileAt(selectedIndexes[0]); + Tile *tile2 = model->tileAt(selectedIndexes[1]); QUndoStack *undoStack = mMapDocument->undoStack(); QUndoCommand *command = new SwapTiles(mMapDocument, tileLayer, tile1, tile2); diff --git a/translations/tiled_de.ts b/translations/tiled_de.ts index 0d921a8e49..3606a1d50f 100644 --- a/translations/tiled_de.ts +++ b/translations/tiled_de.ts @@ -3564,7 +3564,7 @@ Do you want to replace it? - Swap tiles + &Swap Tiles Kacheln ver&tauschen