diff --git a/forms/tileseteditor.ui b/forms/tileseteditor.ui
index f8b6947f..7a56f4a9 100644
--- a/forms/tileseteditor.ui
+++ b/forms/tileseteditor.ui
@@ -407,7 +407,15 @@
+
+
@@ -439,6 +447,22 @@
Change Palettes
+
+
+ Undo
+
+
+ Ctrl+Z
+
+
+
+
+ Redo
+
+
+ Ctrl+Y
+
+
diff --git a/include/core/metatile.h b/include/core/metatile.h
index 4f280608..955c4264 100644
--- a/include/core/metatile.h
+++ b/include/core/metatile.h
@@ -14,6 +14,7 @@ public:
uint8_t layerType;
Metatile *copy();
+ void copyInPlace(Metatile*);
static int getBlockIndex(int);
};
diff --git a/include/ui/metatilelayersitem.h b/include/ui/metatilelayersitem.h
index f76ddc3a..0417f907 100644
--- a/include/ui/metatilelayersitem.h
+++ b/include/ui/metatilelayersitem.h
@@ -13,14 +13,18 @@ public:
this->metatile = metatile;
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
+ this->clearLastModifiedCoords();
}
void draw();
void setTilesets(Tileset*, Tileset*);
void setMetatile(Metatile*);
+ void clearLastModifiedCoords();
private:
Metatile* metatile;
Tileset *primaryTileset;
Tileset *secondaryTileset;
+ QPoint prevChangedTile;
+ void getBoundedCoords(QPointF, int*, int*);
signals:
void tileChanged(int, int);
void selectedTilesChanged(QPoint, int, int);
diff --git a/include/ui/tileseteditor.h b/include/ui/tileseteditor.h
index b4945d8a..776f78cc 100644
--- a/include/ui/tileseteditor.h
+++ b/include/ui/tileseteditor.h
@@ -3,6 +3,7 @@
#include
#include "project.h"
+#include "history.h"
#include "paletteeditor.h"
#include "tileseteditormetatileselector.h"
#include "tileseteditortileselector.h"
@@ -12,6 +13,22 @@ namespace Ui {
class TilesetEditor;
}
+class MetatileHistoryItem {
+public:
+ MetatileHistoryItem(uint16_t metatileId, Metatile *prevMetatile, Metatile *newMetatile) {
+ this->metatileId = metatileId;
+ this->prevMetatile = prevMetatile;
+ this->newMetatile = newMetatile;
+ }
+ ~MetatileHistoryItem() {
+ delete this->prevMetatile;
+ delete this->newMetatile;
+ }
+ uint16_t metatileId;
+ Metatile *prevMetatile;
+ Metatile *newMetatile;
+};
+
class TilesetEditor : public QMainWindow
{
Q_OBJECT
@@ -41,10 +58,6 @@ private slots:
void on_checkBox_yFlip_stateChanged(int arg1);
- void on_comboBox_metatileBehaviors_currentIndexChanged(const QString &arg1);
-
- void on_comboBox_layerType_currentIndexChanged(int index);
-
void on_actionSave_Tileset_triggered();
void on_actionImport_Primary_Tiles_triggered();
@@ -55,6 +68,14 @@ private slots:
void on_actionChange_Palettes_triggered();
+ void on_actionUndo_triggered();
+
+ void on_actionRedo_triggered();
+
+ void on_comboBox_metatileBehaviors_activated(const QString &arg1);
+
+ void on_comboBox_layerType_activated(int arg1);
+
private:
void closeEvent(QCloseEvent*);
void initMetatileSelector();
@@ -65,6 +86,7 @@ private:
void importTilesetTiles(Tileset*, bool);
void refresh();
Ui::TilesetEditor *ui;
+ History metatileHistory;
TilesetEditorMetatileSelector *metatileSelector = nullptr;
TilesetEditorTileSelector *tileSelector = nullptr;
MetatileLayersItem *metatileLayersItem = nullptr;
diff --git a/src/core/metatile.cpp b/src/core/metatile.cpp
index a44b4fa3..e239085d 100644
--- a/src/core/metatile.cpp
+++ b/src/core/metatile.cpp
@@ -18,6 +18,14 @@ Metatile* Metatile::copy() {
return copy;
}
+void Metatile::copyInPlace(Metatile *other) {
+ this->behavior = other->behavior;
+ this->layerType = other->layerType;
+ for (int i = 0; i < this->tiles->length(); i++) {
+ (*this->tiles)[i] = other->tiles->at(i);
+ }
+}
+
int Metatile::getBlockIndex(int index) {
if (index < Project::getNumMetatilesPrimary()) {
return index;
diff --git a/src/ui/metatilelayersitem.cpp b/src/ui/metatilelayersitem.cpp
index f6186a78..68a58492 100644
--- a/src/ui/metatilelayersitem.cpp
+++ b/src/ui/metatilelayersitem.cpp
@@ -29,12 +29,14 @@ void MetatileLayersItem::draw() {
void MetatileLayersItem::setMetatile(Metatile *metatile) {
this->metatile = metatile;
+ this->clearLastModifiedCoords();
}
void MetatileLayersItem::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
this->draw();
+ this->clearLastModifiedCoords();
}
void MetatileLayersItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
@@ -45,17 +47,17 @@ void MetatileLayersItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
emit this->selectedTilesChanged(selectionOrigin, dimensions.x(), dimensions.y());
this->drawSelection();
} else {
- QPointF pos = event->pos();
- int x = static_cast(pos.x()) / 16;
- int y = static_cast(pos.y()) / 16;
- emit this->tileChanged(x, y);
+ int x, y;
+ this->getBoundedCoords(event->pos(), &x, &y);
+ if (prevChangedTile.x() != x || prevChangedTile.y() != y) {
+ this->prevChangedTile.setX(x);
+ this->prevChangedTile.setY(y);
+ emit this->tileChanged(x, y);
+ }
}
}
void MetatileLayersItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
- QPointF pos = event->pos();
- int x = static_cast(pos.x()) / 16;
- int y = static_cast(pos.y()) / 16;
if (event->buttons() & Qt::RightButton) {
SelectablePixmapItem::mouseMoveEvent(event);
QPoint selectionOrigin = this->getSelectionStart();
@@ -63,7 +65,13 @@ void MetatileLayersItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
emit this->selectedTilesChanged(selectionOrigin, dimensions.x(), dimensions.y());
this->drawSelection();
} else {
- emit this->tileChanged(x, y);
+ int x, y;
+ this->getBoundedCoords(event->pos(), &x, &y);
+ if (prevChangedTile.x() != x || prevChangedTile.y() != y) {
+ this->prevChangedTile.setX(x);
+ this->prevChangedTile.setY(y);
+ emit this->tileChanged(x, y);
+ }
}
}
@@ -77,3 +85,17 @@ void MetatileLayersItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
this->draw();
}
+
+void MetatileLayersItem::clearLastModifiedCoords() {
+ this->prevChangedTile.setX(-1);
+ this->prevChangedTile.setY(-1);
+}
+
+void MetatileLayersItem::getBoundedCoords(QPointF pos, int *x, int *y) {
+ *x = static_cast(pos.x()) / 16;
+ *y = static_cast(pos.y()) / 16;
+ if (*x < 0) *x = 0;
+ if (*y < 0) *y = 0;
+ if (*x > 3) *x = 3;
+ if (*y > 1) *y = 1;
+}
diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp
index 773ed4d8..56adc6a5 100644
--- a/src/ui/tileseteditor.cpp
+++ b/src/ui/tileseteditor.cpp
@@ -49,6 +49,9 @@ void TilesetEditor::init(Project *project, QString primaryTilesetLabel, QString
this->initTileSelector();
this->initSelectedTileItem();
this->metatileSelector->select(0);
+
+ MetatileHistoryItem *commit = new MetatileHistoryItem(0, nullptr, this->metatile->copy());
+ metatileHistory.push(commit);
}
void TilesetEditor::setTilesets(QString primaryTilesetLabel, QString secondaryTilesetLabel) {
@@ -191,6 +194,7 @@ void TilesetEditor::onSelectedTilesChanged() {
}
void TilesetEditor::onMetatileLayerTileChanged(int x, int y) {
+ Metatile *prevMetatile = this->metatile->copy();
int maxTileIndex = x < 2 ? 3 : 7;
QPoint dimensions = this->tileSelector->getSelectionDimensions();
QList tiles = this->tileSelector->getSelectedTiles();
@@ -213,6 +217,9 @@ void TilesetEditor::onMetatileLayerTileChanged(int x, int y) {
this->metatileSelector->draw();
this->metatileLayersItem->draw();
this->hasUnsavedChanges = true;
+
+ MetatileHistoryItem *commit = new MetatileHistoryItem(metatileSelector->getSelectedMetatile(), prevMetatile, this->metatile->copy());
+ metatileHistory.push(commit);
}
void TilesetEditor::onMetatileLayerSelectionChanged(QPoint selectionOrigin, int width, int height) {
@@ -228,6 +235,7 @@ void TilesetEditor::onMetatileLayerSelectionChanged(QPoint selectionOrigin, int
}
}
this->tileSelector->setExternalSelection(width, height, tiles);
+ this->metatileLayersItem->clearLastModifiedCoords();
}
void TilesetEditor::on_spinBox_paletteSelector_valueChanged(int paletteId)
@@ -241,6 +249,7 @@ void TilesetEditor::on_spinBox_paletteSelector_valueChanged(int paletteId)
if (this->paletteEditor) {
this->paletteEditor->setPaletteId(paletteId);
}
+ this->metatileLayersItem->clearLastModifiedCoords();
}
void TilesetEditor::on_checkBox_xFlip_stateChanged(int checked)
@@ -248,6 +257,7 @@ void TilesetEditor::on_checkBox_xFlip_stateChanged(int checked)
this->tileXFlip = checked;
this->tileSelector->setTileFlips(this->tileXFlip, this->tileYFlip);
this->drawSelectedTiles();
+ this->metatileLayersItem->clearLastModifiedCoords();
}
void TilesetEditor::on_checkBox_yFlip_stateChanged(int checked)
@@ -255,19 +265,26 @@ void TilesetEditor::on_checkBox_yFlip_stateChanged(int checked)
this->tileYFlip = checked;
this->tileSelector->setTileFlips(this->tileXFlip, this->tileYFlip);
this->drawSelectedTiles();
+ this->metatileLayersItem->clearLastModifiedCoords();
}
-void TilesetEditor::on_comboBox_metatileBehaviors_currentIndexChanged(const QString &metatileBehavior)
+void TilesetEditor::on_comboBox_metatileBehaviors_activated(const QString &metatileBehavior)
{
if (this->metatile) {
+ Metatile *prevMetatile = this->metatile->copy();
this->metatile->behavior = static_cast(project->metatileBehaviorMap[metatileBehavior]);
+ MetatileHistoryItem *commit = new MetatileHistoryItem(metatileSelector->getSelectedMetatile(), prevMetatile, this->metatile->copy());
+ metatileHistory.push(commit);
}
}
-void TilesetEditor::on_comboBox_layerType_currentIndexChanged(int layerType)
+void TilesetEditor::on_comboBox_layerType_activated(int layerType)
{
if (this->metatile) {
+ Metatile *prevMetatile = this->metatile->copy();
this->metatile->layerType = static_cast(layerType);
+ MetatileHistoryItem *commit = new MetatileHistoryItem(metatileSelector->getSelectedMetatile(), prevMetatile, this->metatile->copy());
+ metatileHistory.push(commit);
}
}
@@ -475,3 +492,40 @@ void TilesetEditor::onPaletteEditorChangedPaletteColor() {
void TilesetEditor::onPaletteEditorChangedPalette(int paletteId) {
this->on_spinBox_paletteSelector_valueChanged(paletteId);
}
+
+void TilesetEditor::on_actionUndo_triggered()
+{
+ MetatileHistoryItem *commit = this->metatileHistory.current();
+ if (!commit) return;
+ Metatile *prev = commit->prevMetatile;
+ if (!prev) return;
+ this->metatileHistory.back();
+
+ Metatile *temp = Tileset::getMetatile(commit->metatileId, this->primaryTileset, this->secondaryTileset);
+ if (temp) {
+ this->metatile = temp;
+ this->metatile->copyInPlace(prev);
+ this->metatileSelector->select(commit->metatileId);
+ this->metatileSelector->draw();
+ this->metatileLayersItem->draw();
+ this->metatileLayersItem->clearLastModifiedCoords();
+ }
+}
+
+void TilesetEditor::on_actionRedo_triggered()
+{
+ MetatileHistoryItem *commit = this->metatileHistory.next();
+ if (!commit) return;
+ Metatile *next = commit->newMetatile;
+ if (!next) return;
+
+ Metatile *temp = Tileset::getMetatile(commit->metatileId, this->primaryTileset, this->secondaryTileset);
+ if (temp) {
+ this->metatile = Tileset::getMetatile(commit->metatileId, this->primaryTileset, this->secondaryTileset);
+ this->metatile->copyInPlace(next);
+ this->metatileSelector->select(commit->metatileId);
+ this->metatileSelector->draw();
+ this->metatileLayersItem->draw();
+ this->metatileLayersItem->clearLastModifiedCoords();
+ }
+}