diff --git a/CHANGELOG.md b/CHANGELOG.md index 19ccb55e..af961fa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ The **"Breaking Changes"** listed below are changes that have been made in the d - Fix null characters being unpredictably written to some JSON files. - Fix tilesets that share part of their name loading incorrectly. - Fix events being hidden behind connecting maps. +- Metatile labels with values defined outside their tileset are no longer deleted. +- Fix the Tileset Editor retaining edit history after changing tilesets. - Fix some minor visual issues on the Connections tab. - Fix bug which caused encounter configurator to crash if slots in fields containing groups were deleted. - Fix bug which caused encounter configurator to crash if last field was deleted. diff --git a/docsrc/manual/tileset-editor.rst b/docsrc/manual/tileset-editor.rst index df9cfb95..83b10012 100644 --- a/docsrc/manual/tileset-editor.rst +++ b/docsrc/manual/tileset-editor.rst @@ -76,12 +76,19 @@ Metatile Label *optional* A name can be given to metatiles so that they may be referenced in source code. -These are defined in ``include/constants/metatile_labels.h`` and can be used in -together with the ``METATILE_ID`` macro. +These are defined in ``include/constants/metatile_labels.h``. -For example, the metatile pictured above can be accessed like -``METATILE_ID(General, Plain_Grass)``. +For example, the metatile pictured above can be referenced using the define +``METATILE_General_Plain_Grass``. +This define name can be copied using the Copy button next to the metatile label text box. +Sometimes it may be useful to have a ``METATILE`` define that applies to many tilesets. +This can be done by manually creating a ``METATILE`` define with a value outside its tileset. +For example, the primary tileset ``SecretBase`` is associated with many secondary tilesets, +all of which use the same labels. ``#define METATILE_SecretBase_PC 0x220`` defines a label +for the secondary metatile id ``0x220`` which will be used by any secondary tileset that's +paired with ``SecretBase``. Labels like this will appear gray in the text box, and can't +be edited from within Porymap; they must be edited manually in ``metatile_labels.h``. diff --git a/include/core/history.h b/include/core/history.h index 0c26780c..c999a4e1 100644 --- a/include/core/history.h +++ b/include/core/history.h @@ -10,9 +10,15 @@ public: History() { } ~History() { + clear(); + } + + void clear() { while (!history.isEmpty()) { delete history.takeLast(); } + head = -1; + saved = -1; } T back() { diff --git a/include/core/metatile.h b/include/core/metatile.h index f606dcdb..49fb5c7b 100644 --- a/include/core/metatile.h +++ b/include/core/metatile.h @@ -70,7 +70,6 @@ public: uint32_t encounterType; uint32_t layerType; uint32_t unusedAttributes; - QString label; uint32_t getAttributes(); void setAttributes(uint32_t data); @@ -121,7 +120,6 @@ inline bool operator==(const Metatile &a, const Metatile &b) { a.encounterType == b.encounterType && a.terrainType == b.terrainType && a.unusedAttributes == b.unusedAttributes && - a.label == b.label && a.tiles == b.tiles; } diff --git a/include/core/tileset.h b/include/core/tileset.h index 2c6d658e..3f50f41b 100644 --- a/include/core/tileset.h +++ b/include/core/tileset.h @@ -5,6 +5,12 @@ #include "metatile.h" #include "tile.h" #include +#include + +struct MetatileLabelPair { + QString owned; + QString shared; +}; class Tileset { @@ -28,12 +34,20 @@ public: QList tiles; QList metatiles; + QHash metatileLabels; QList> palettes; QList> palettePreviews; static Tileset* getMetatileTileset(int, Tileset*, Tileset*); static Tileset* getTileTileset(int, Tileset*, Tileset*); static Metatile* getMetatile(int, Tileset*, Tileset*); + static Tileset* getMetatileLabelTileset(int, Tileset*, Tileset*); + static QString getMetatileLabel(int, Tileset *, Tileset *); + static QString getOwnedMetatileLabel(int, Tileset *, Tileset *); + static MetatileLabelPair getMetatileLabelPair(int metatileId, Tileset *primaryTileset, Tileset *secondaryTileset); + static bool setMetatileLabel(int, QString, Tileset *, Tileset *); + QString getMetatileLabelPrefix(); + static QString getMetatileLabelPrefix(const QString &name); static QList> getBlockPalettes(Tileset*, Tileset*, bool useTruePalettes = false); static QList getPalette(int, Tileset*, Tileset*, bool useTruePalettes = false); static bool metatileIsValid(uint16_t metatileId, Tileset *, Tileset *); diff --git a/include/ui/tileseteditor.h b/include/ui/tileseteditor.h index fcdd3bed..b03964b5 100644 --- a/include/ui/tileseteditor.h +++ b/include/ui/tileseteditor.h @@ -16,10 +16,12 @@ class TilesetEditor; class MetatileHistoryItem { public: - MetatileHistoryItem(uint16_t metatileId, Metatile *prevMetatile, Metatile *newMetatile) { + MetatileHistoryItem(uint16_t metatileId, Metatile *prevMetatile, Metatile *newMetatile, QString prevLabel, QString newLabel) { this->metatileId = metatileId; this->prevMetatile = prevMetatile; this->newMetatile = newMetatile; + this->prevLabel = prevLabel; + this->newLabel = newLabel; } ~MetatileHistoryItem() { delete this->prevMetatile; @@ -28,6 +30,8 @@ public: uint16_t metatileId; Metatile *prevMetatile; Metatile *newMetatile; + QString prevLabel; + QString newLabel; }; class TilesetEditor : public QMainWindow @@ -127,14 +131,16 @@ private: void importTilesetTiles(Tileset*, bool); void importTilesetMetatiles(Tileset*, bool); void refresh(); - void saveMetatileLabel(); + void commitMetatileLabel(); void closeEvent(QCloseEvent*); void countMetatileUsage(); void countTileUsage(); void copyMetatile(bool cut); - void pasteMetatile(const Metatile * toPaste); - bool replaceMetatile(uint16_t metatileId, const Metatile * src); + void pasteMetatile(const Metatile * toPaste, QString label); + bool replaceMetatile(uint16_t metatileId, const Metatile * src, QString label); void setComboValue(QComboBox * combo, int value); + void commitMetatileChange(Metatile * prevMetatile); + void commitMetatileAndLabelChange(Metatile * prevMetatile, QString prevLabel); Ui::TilesetEditor *ui; History metatileHistory; @@ -146,6 +152,7 @@ private: Map *map = nullptr; Metatile *metatile = nullptr; Metatile *copiedMetatile = nullptr; + QString copiedMetatileLabel; int paletteId; bool tileXFlip; bool tileYFlip; diff --git a/src/core/tileset.cpp b/src/core/tileset.cpp index e3d00d8c..4809ba6d 100644 --- a/src/core/tileset.cpp +++ b/src/core/tileset.cpp @@ -20,6 +20,7 @@ Tileset::Tileset(const Tileset &other) tilesImagePath(other.tilesImagePath), tilesImage(other.tilesImage.copy()), palettePaths(other.palettePaths), + metatileLabels(other.metatileLabels), palettes(other.palettes), palettePreviews(other.palettePreviews) { @@ -44,6 +45,7 @@ Tileset &Tileset::operator=(const Tileset &other) { tilesImagePath = other.tilesImagePath; tilesImage = other.tilesImage.copy(); palettePaths = other.palettePaths; + metatileLabels = other.metatileLabels; palettes = other.palettes; palettePreviews = other.palettePreviews; @@ -82,13 +84,92 @@ Tileset* Tileset::getMetatileTileset(int metatileId, Tileset *primaryTileset, Ti Metatile* Tileset::getMetatile(int metatileId, Tileset *primaryTileset, Tileset *secondaryTileset) { Tileset *tileset = Tileset::getMetatileTileset(metatileId, primaryTileset, secondaryTileset); - int index = Metatile::getIndexInTileset(metatileId); if (!tileset) { return nullptr; } + int index = Metatile::getIndexInTileset(metatileId); return tileset->metatiles.value(index, nullptr); } +// Metatile labels are stored per-tileset. When looking for a metatile label, first search in the tileset +// that the metatile belongs to. If one isn't found, search in the other tileset. Labels coming from the +// tileset that the metatile does not belong to are shared and cannot be edited via Porymap. +Tileset* Tileset::getMetatileLabelTileset(int metatileId, Tileset *primaryTileset, Tileset *secondaryTileset) { + Tileset *mainTileset = nullptr; + Tileset *alternateTileset = nullptr; + if (metatileId < Project::getNumMetatilesPrimary()) { + mainTileset = primaryTileset; + alternateTileset = secondaryTileset; + } else if (metatileId < Project::getNumMetatilesTotal()) { + mainTileset = secondaryTileset; + alternateTileset = primaryTileset; + } + + if (mainTileset && !mainTileset->metatileLabels.value(metatileId).isEmpty()) { + return mainTileset; + } else if (alternateTileset && !alternateTileset->metatileLabels.value(metatileId).isEmpty()) { + return alternateTileset; + } + return nullptr; +} + +// Return the pair of possible metatile labels for the specified metatile. +// "owned" is the label for the tileset to which the metatile belongs. +// "shared" is the label for the tileset to which the metatile does not belong. +MetatileLabelPair Tileset::getMetatileLabelPair(int metatileId, Tileset *primaryTileset, Tileset *secondaryTileset) { + MetatileLabelPair labels; + QString primaryMetatileLabel = primaryTileset ? primaryTileset->metatileLabels.value(metatileId) : ""; + QString secondaryMetatileLabel = secondaryTileset ? secondaryTileset->metatileLabels.value(metatileId) : ""; + + if (metatileId < Project::getNumMetatilesPrimary()) { + labels.owned = primaryMetatileLabel; + labels.shared = secondaryMetatileLabel; + } else if (metatileId < Project::getNumMetatilesTotal()) { + labels.owned = secondaryMetatileLabel; + labels.shared = primaryMetatileLabel; + } + return labels; +} + +// If the metatile has a label in the tileset it belongs to, return that label. +// If it doesn't, and the metatile has a label in the other tileset, return that label. +// Otherwise return an empty string. +QString Tileset::getMetatileLabel(int metatileId, Tileset *primaryTileset, Tileset *secondaryTileset) { + MetatileLabelPair labels = Tileset::getMetatileLabelPair(metatileId, primaryTileset, secondaryTileset); + return !labels.owned.isEmpty() ? labels.owned : labels.shared; +} + +// Just get the "owned" metatile label, i.e. the one for the tileset that the metatile belongs to. +QString Tileset::getOwnedMetatileLabel(int metatileId, Tileset *primaryTileset, Tileset *secondaryTileset) { + MetatileLabelPair labels = Tileset::getMetatileLabelPair(metatileId, primaryTileset, secondaryTileset); + return labels.owned; +} + +bool Tileset::setMetatileLabel(int metatileId, QString label, Tileset *primaryTileset, Tileset *secondaryTileset) { + Tileset *tileset = Tileset::getMetatileTileset(metatileId, primaryTileset, secondaryTileset); + if (!tileset) + return false; + + static const QRegularExpression expression("[_A-Za-z0-9]*$"); + QRegularExpressionValidator validator(expression); + int pos = 0; + if (validator.validate(label, pos) != QValidator::Acceptable) + return false; + + tileset->metatileLabels[metatileId] = label; + return true; +} + +QString Tileset::getMetatileLabelPrefix() +{ + return Tileset::getMetatileLabelPrefix(this->name); +} + +QString Tileset::getMetatileLabelPrefix(const QString &name) +{ + return QString("METATILE_%1_").arg(QString(name).replace("gTileset_", "")); +} + bool Tileset::metatileIsValid(uint16_t metatileId, Tileset *primaryTileset, Tileset *secondaryTileset) { if (metatileId >= Project::getNumMetatilesTotal()) return false; diff --git a/src/editor.cpp b/src/editor.cpp index c3d98936..76124324 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -932,14 +932,13 @@ void Editor::onHoveredMovementPermissionCleared() { QString Editor::getMetatileDisplayMessage(uint16_t metatileId) { Metatile *metatile = Tileset::getMetatile(metatileId, map->layout->tileset_primary, map->layout->tileset_secondary); + QString label = Tileset::getMetatileLabel(metatileId, map->layout->tileset_primary, map->layout->tileset_secondary); QString hexString = QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper(); QString message = QString("Metatile: 0x%1").arg(hexString); - if (metatile) { - if (metatile->label.size()) - message += QString(" \"%1\"").arg(metatile->label); - if (metatile->behavior) // Skip MB_NORMAL - message += QString(", Behavior: %1").arg(this->project->metatileBehaviorMapInverse.value(metatile->behavior, QString::number(metatile->behavior))); - } + if (label.size()) + message += QString(" \"%1\"").arg(label); + if (metatile && metatile->behavior) // Skip MB_NORMAL + message += QString(", Behavior: %1").arg(this->project->metatileBehaviorMapInverse.value(metatile->behavior, QString::number(metatile->behavior))); return message; } diff --git a/src/project.cpp b/src/project.cpp index 095e540c..b0e3d43c 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -891,8 +891,8 @@ void Project::saveTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) { } void Project::saveTilesetMetatileLabels(Tileset *primaryTileset, Tileset *secondaryTileset) { - QString primaryPrefix = QString("METATILE_%1_").arg(QString(primaryTileset->name).replace("gTileset_", "")); - QString secondaryPrefix = QString("METATILE_%1_").arg(QString(secondaryTileset->name).replace("gTileset_", "")); + QString primaryPrefix = primaryTileset->getMetatileLabelPrefix(); + QString secondaryPrefix = secondaryTileset->getMetatileLabelPrefix(); QMap defines; bool definesFileModified = false; @@ -913,21 +913,19 @@ void Project::saveTilesetMetatileLabels(Tileset *primaryTileset, Tileset *second } // Add the new labels. - for (int i = 0; i < primaryTileset->metatiles.size(); i++) { - Metatile *metatile = primaryTileset->metatiles.at(i); - if (metatile->label.size() != 0) { - QString defineName = QString("%1%2").arg(primaryPrefix, metatile->label); - defines.insert(defineName, i); - definesFileModified = true; - } + for (int metatileId : primaryTileset->metatileLabels.keys()) { + QString label = primaryTileset->metatileLabels.value(metatileId); + if (label.isEmpty()) continue; + QString defineName = QString("%1%2").arg(primaryPrefix, label); + defines.insert(defineName, metatileId); + definesFileModified = true; } - for (int i = 0; i < secondaryTileset->metatiles.size(); i++) { - Metatile *metatile = secondaryTileset->metatiles.at(i); - if (metatile->label.size() != 0) { - QString defineName = QString("%1%2").arg(secondaryPrefix, metatile->label); - defines.insert(defineName, i + Project::num_tiles_primary); - definesFileModified = true; - } + for (int metatileId : secondaryTileset->metatileLabels.keys()) { + QString label = secondaryTileset->metatileLabels.value(metatileId); + if (label.isEmpty()) continue; + QString defineName = QString("%1%2").arg(secondaryPrefix, label); + defines.insert(defineName, metatileId); + definesFileModified = true; } if (!definesFileModified) { @@ -1506,11 +1504,11 @@ bool Project::readTilesetMetatileLabels() { QMap labels = parser.readCDefines(metatileLabelsFilename, QStringList() << "METATILE_"); - for (QString label : this->tilesetLabelsOrdered) { - QString tilesetName = QString(label).replace("gTileset_", ""); + for (QString tilesetLabel : this->tilesetLabelsOrdered) { + QString metatileLabelPrefix = Tileset::getMetatileLabelPrefix(tilesetLabel); for (QString key : labels.keys()) { - if (key.contains(QString("METATILE_") + tilesetName)) { - metatileLabelsMap[label][key] = labels[key]; + if (key.startsWith(metatileLabelPrefix)) { + metatileLabelsMap[tilesetLabel][key] = labels[key]; } } } @@ -1519,19 +1517,12 @@ bool Project::readTilesetMetatileLabels() { } void Project::loadTilesetMetatileLabels(Tileset* tileset) { - QString tilesetPrefix = QString("METATILE_%1_").arg(QString(tileset->name).replace("gTileset_", "")); + QString metatileLabelPrefix = tileset->getMetatileLabelPrefix(); + // Reverse map for faster lookup by metatile id for (QString labelName : metatileLabelsMap[tileset->name].keys()) { int metatileId = metatileLabelsMap[tileset->name][labelName]; - // subtract Project::num_tiles_primary from secondary metatiles - int offset = tileset->is_secondary ? Project::num_tiles_primary : 0; - Metatile *metatile = Tileset::getMetatile(metatileId - offset, tileset, nullptr); - if (metatile) { - metatile->label = labelName.replace(tilesetPrefix, ""); - } else { - QString hexString = QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper(); - logError(QString("Metatile 0x%1 (%2) cannot be found in tileset '%3'").arg(hexString, labelName, tileset->name)); - } + tileset->metatileLabels[metatileId] = labelName.replace(metatileLabelPrefix, ""); } } diff --git a/src/scriptapi/apimap.cpp b/src/scriptapi/apimap.cpp index 046474de..fde049db 100644 --- a/src/scriptapi/apimap.cpp +++ b/src/scriptapi/apimap.cpp @@ -598,32 +598,28 @@ Metatile * MainWindow::getMetatile(int metatileId) { } QString MainWindow::getMetatileLabel(int metatileId) { - Metatile * metatile = this->getMetatile(metatileId); - if (!metatile || metatile->label.size() == 0) + if (!this->editor || !this->editor->map || !this->editor->map->layout) return QString(); - return metatile->label; + return Tileset::getMetatileLabel(metatileId, this->editor->map->layout->tileset_primary, this->editor->map->layout->tileset_secondary); } void MainWindow::setMetatileLabel(int metatileId, QString label) { - Metatile * metatile = this->getMetatile(metatileId); - if (!metatile) + if (!this->editor || !this->editor->map || !this->editor->map->layout) return; - static const QRegularExpression expression("[_A-Za-z0-9]*$"); - QRegularExpressionValidator validator(expression); - int pos = 0; - if (validator.validate(label, pos) != QValidator::Acceptable) { - logError(QString("Invalid metatile label %1").arg(label)); - return; - } - - if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatileId() == metatileId) { + // If the Tileset Editor is opened on this metatile we need to update the text box + if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatileId() == metatileId){ this->tilesetEditor->setMetatileLabel(label); - } else if (metatile->label != label) { - metatile->label = label; - if (this->editor->project) - this->editor->project->saveTilesetMetatileLabels(this->editor->map->layout->tileset_primary, this->editor->map->layout->tileset_secondary); + return; } + + if (!Tileset::setMetatileLabel(metatileId, label, this->editor->map->layout->tileset_primary, this->editor->map->layout->tileset_secondary)) { + logError("Failed to set metatile label. Must be a valid metatile id and a label containing only letters, numbers, and underscores."); + return; + } + + if (this->editor->project) + this->editor->project->saveTilesetMetatileLabels(this->editor->map->layout->tileset_primary, this->editor->map->layout->tileset_secondary); } int MainWindow::getMetatileLayerType(int metatileId) { diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 7f5d7695..c16aeaf4 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -22,7 +22,6 @@ TilesetEditor::TilesetEditor(Project *project, Map *map, QWidget *parent) : { this->setTilesets(this->map->layout->tileset_primary_label, this->map->layout->tileset_secondary_label); this->initUi(); - this->initMetatileHistory(); } TilesetEditor::~TilesetEditor() @@ -64,7 +63,6 @@ void TilesetEditor::updateTilesets(QString primaryTilesetLabel, QString secondar if (result == QMessageBox::Yes) this->on_actionSave_Tileset_triggered(); } - this->hasUnsavedChanges = false; this->setTilesets(primaryTilesetLabel, secondaryTilesetLabel); this->refresh(); } @@ -89,6 +87,7 @@ void TilesetEditor::setTilesets(QString primaryTilesetLabel, QString secondaryTi this->primaryTileset = new Tileset(*primaryTileset); this->secondaryTileset = new Tileset(*secondaryTileset); if (paletteEditor) paletteEditor->setTilesets(this->primaryTileset, this->secondaryTileset); + this->initMetatileHistory(); } void TilesetEditor::initUi() { @@ -276,12 +275,13 @@ void TilesetEditor::restoreWindowState() { } void TilesetEditor::initMetatileHistory() { - MetatileHistoryItem *commit = new MetatileHistoryItem(0, nullptr, new Metatile(*metatile)); + metatileHistory.clear(); + MetatileHistoryItem *commit = new MetatileHistoryItem(0, nullptr, new Metatile(), QString(), QString()); metatileHistory.push(commit); + this->hasUnsavedChanges = false; } void TilesetEditor::reset() { - this->hasUnsavedChanges = false; this->setTilesets(this->primaryTileset->name, this->secondaryTileset->name); if (this->paletteEditor) this->paletteEditor->setTilesets(this->primaryTileset, this->secondaryTileset); @@ -343,13 +343,11 @@ void TilesetEditor::drawSelectedTiles() { } void TilesetEditor::onHoveredMetatileChanged(uint16_t metatileId) { - Metatile *metatile = Tileset::getMetatile(metatileId, this->primaryTileset, this->secondaryTileset); - QString message; + QString label = Tileset::getMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset); QString hexString = QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper(); - if (metatile && metatile->label.size() != 0) { - message = QString("Metatile: 0x%1 \"%2\"").arg(hexString, metatile->label); - } else { - message = QString("Metatile: 0x%1").arg(hexString); + QString message = QString("Metatile: 0x%1").arg(hexString); + if (label.size() != 0) { + message += QString(" \"%1\"").arg(label); } this->ui->statusbar->showMessage(message); } @@ -381,7 +379,11 @@ void TilesetEditor::onSelectedMetatileChanged(uint16_t metatileId) { this->metatileLayersItem->setMetatile(metatile); this->metatileLayersItem->draw(); this->ui->graphicsView_metatileLayers->setFixedSize(this->metatileLayersItem->pixmap().width() + 2, this->metatileLayersItem->pixmap().height() + 2); - this->ui->lineEdit_metatileLabel->setText(this->metatile->label); + + MetatileLabelPair labels = Tileset::getMetatileLabelPair(metatileId, this->primaryTileset, this->secondaryTileset); + this->ui->lineEdit_metatileLabel->setText(labels.owned); + this->ui->lineEdit_metatileLabel->setPlaceholderText(labels.shared); + setComboValue(this->ui->comboBox_metatileBehaviors, this->metatile->behavior); setComboValue(this->ui->comboBox_layerType, this->metatile->layerType); setComboValue(this->ui->comboBox_encounterType, this->metatile->encounterType); @@ -440,11 +442,7 @@ void TilesetEditor::onMetatileLayerTileChanged(int x, int y) { this->metatileSelector->draw(); this->metatileLayersItem->draw(); - this->hasUnsavedChanges = true; - - MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(), - prevMetatile, new Metatile(*this->metatile)); - metatileHistory.push(commit); + this->commitMetatileChange(prevMetatile); } void TilesetEditor::onMetatileLayerSelectionChanged(QPoint selectionOrigin, int width, int height) { @@ -523,46 +521,53 @@ void TilesetEditor::on_comboBox_metatileBehaviors_currentTextChanged(const QStri Metatile *prevMetatile = new Metatile(*this->metatile); this->metatile->setBehavior(behavior); - MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(), - prevMetatile, new Metatile(*this->metatile)); - metatileHistory.push(commit); - this->hasUnsavedChanges = true; + this->commitMetatileChange(prevMetatile); } } void TilesetEditor::setMetatileLabel(QString label) { this->ui->lineEdit_metatileLabel->setText(label); - saveMetatileLabel(); + commitMetatileLabel(); } void TilesetEditor::on_lineEdit_metatileLabel_editingFinished() { - saveMetatileLabel(); + commitMetatileLabel(); } -void TilesetEditor::saveMetatileLabel() +void TilesetEditor::commitMetatileLabel() { // Only commit if the field has changed. - if (this->metatile && this->metatile->label != this->ui->lineEdit_metatileLabel->text()) { + uint16_t metatileId = this->getSelectedMetatileId(); + QString oldLabel = Tileset::getOwnedMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset); + QString newLabel = this->ui->lineEdit_metatileLabel->text(); + if (oldLabel != newLabel) { Metatile *prevMetatile = new Metatile(*this->metatile); - this->metatile->label = this->ui->lineEdit_metatileLabel->text(); - MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(), - prevMetatile, new Metatile(*this->metatile)); - metatileHistory.push(commit); - this->hasUnsavedChanges = true; + Tileset::setMetatileLabel(metatileId, newLabel, this->primaryTileset, this->secondaryTileset); + this->commitMetatileAndLabelChange(prevMetatile, oldLabel); } } +void TilesetEditor::commitMetatileAndLabelChange(Metatile * prevMetatile, QString prevLabel) +{ + metatileHistory.push(new MetatileHistoryItem(this->getSelectedMetatileId(), + prevMetatile, new Metatile(*this->metatile), + prevLabel, this->ui->lineEdit_metatileLabel->text())); + this->hasUnsavedChanges = true; +} + +void TilesetEditor::commitMetatileChange(Metatile * prevMetatile) +{ + this->commitMetatileAndLabelChange(prevMetatile, this->ui->lineEdit_metatileLabel->text()); +} + void TilesetEditor::on_comboBox_layerType_activated(int layerType) { if (this->metatile) { Metatile *prevMetatile = new Metatile(*this->metatile); this->metatile->setLayerType(layerType); - MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(), - prevMetatile, new Metatile(*this->metatile)); - metatileHistory.push(commit); - this->hasUnsavedChanges = true; + this->commitMetatileChange(prevMetatile); this->metatileSelector->draw(); // Changing the layer type can affect how fully transparent metatiles appear } } @@ -572,10 +577,7 @@ void TilesetEditor::on_comboBox_encounterType_activated(int encounterType) if (this->metatile) { Metatile *prevMetatile = new Metatile(*this->metatile); this->metatile->setEncounterType(encounterType); - MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(), - prevMetatile, new Metatile(*this->metatile)); - metatileHistory.push(commit); - this->hasUnsavedChanges = true; + this->commitMetatileChange(prevMetatile); } } @@ -584,10 +586,7 @@ void TilesetEditor::on_comboBox_terrainType_activated(int terrainType) if (this->metatile) { Metatile *prevMetatile = new Metatile(*this->metatile); this->metatile->setTerrainType(terrainType); - MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(), - prevMetatile, new Metatile(*this->metatile)); - metatileHistory.push(commit); - this->hasUnsavedChanges = true; + this->commitMetatileChange(prevMetatile); } } @@ -597,8 +596,6 @@ void TilesetEditor::on_actionSave_Tileset_triggered() // when the tilesetsSaved signal is sent, it will be reset to the current map metatile uint16_t reselectMetatileID = this->metatileSelector->getSelectedMetatileId(); - saveMetatileLabel(); - this->project->saveTilesets(this->primaryTileset, this->secondaryTileset); emit this->tilesetsSaved(this->primaryTileset->name, this->secondaryTileset->name); this->metatileSelector->select(reselectMetatileID); @@ -845,12 +842,17 @@ void TilesetEditor::onPaletteEditorChangedPalette(int paletteId) { this->on_spinBox_paletteSelector_valueChanged(paletteId); } -bool TilesetEditor::replaceMetatile(uint16_t metatileId, const Metatile * src) +bool TilesetEditor::replaceMetatile(uint16_t metatileId, const Metatile * src, QString newLabel) { Metatile * dest = Tileset::getMetatile(metatileId, this->primaryTileset, this->secondaryTileset); - if (!dest || !src || *dest == *src) + QString oldLabel = Tileset::getOwnedMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset); + if (!dest || !src || (*dest == *src && oldLabel == newLabel)) return false; + Tileset::setMetatileLabel(metatileId, newLabel, this->primaryTileset, this->secondaryTileset); + if (metatileId == this->getSelectedMetatileId()) + this->ui->lineEdit_metatileLabel->setText(newLabel); + this->metatile = dest; *this->metatile = *src; this->metatileSelector->select(metatileId); @@ -867,21 +869,21 @@ void TilesetEditor::on_actionUndo_triggered() Metatile *prev = commit->prevMetatile; if (!prev) return; this->metatileHistory.back(); - this->replaceMetatile(commit->metatileId, prev); + this->replaceMetatile(commit->metatileId, prev, commit->prevLabel); } void TilesetEditor::on_actionRedo_triggered() { MetatileHistoryItem *commit = this->metatileHistory.next(); if (!commit) return; - this->replaceMetatile(commit->metatileId, commit->newMetatile); + this->replaceMetatile(commit->metatileId, commit->newMetatile, commit->newLabel); } void TilesetEditor::on_actionCut_triggered() { Metatile * empty = new Metatile(projectConfig.getNumTilesInMetatile()); this->copyMetatile(true); - this->pasteMetatile(empty); + this->pasteMetatile(empty, ""); delete empty; } @@ -892,32 +894,35 @@ void TilesetEditor::on_actionCopy_triggered() void TilesetEditor::on_actionPaste_triggered() { - this->pasteMetatile(this->copiedMetatile); + this->pasteMetatile(this->copiedMetatile, this->copiedMetatileLabel); } void TilesetEditor::copyMetatile(bool cut) { - Metatile * toCopy = Tileset::getMetatile(this->getSelectedMetatileId(), this->primaryTileset, this->secondaryTileset); + uint16_t metatileId = this->getSelectedMetatileId(); + Metatile * toCopy = Tileset::getMetatile(metatileId, this->primaryTileset, this->secondaryTileset); if (!toCopy) return; if (!this->copiedMetatile) this->copiedMetatile = new Metatile(*toCopy); else *this->copiedMetatile = *toCopy; - if (!cut) this->copiedMetatile->label = ""; // Don't copy the label unless it's a cut, these should be unique to each metatile + + // Don't try to copy the label unless it's a cut, these should be unique to each metatile. + this->copiedMetatileLabel = cut ? Tileset::getOwnedMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset) : QString(); } -void TilesetEditor::pasteMetatile(const Metatile * toPaste) +void TilesetEditor::pasteMetatile(const Metatile * toPaste, QString newLabel) { Metatile *prevMetatile = new Metatile(*this->metatile); + QString prevLabel = this->ui->lineEdit_metatileLabel->text(); + if (newLabel.isNull()) newLabel = prevLabel; // Don't change the label if one wasn't copied uint16_t metatileId = this->getSelectedMetatileId(); - if (!this->replaceMetatile(metatileId, toPaste)) { + if (!this->replaceMetatile(metatileId, toPaste, newLabel)) { delete prevMetatile; return; } - MetatileHistoryItem *commit = new MetatileHistoryItem(metatileId, prevMetatile, new Metatile(*this->metatile)); - metatileHistory.push(commit); - this->hasUnsavedChanges = true; + this->commitMetatileAndLabelChange(prevMetatile, prevLabel); } void TilesetEditor::on_actionExport_Primary_Tiles_Image_triggered() @@ -1013,9 +1018,12 @@ void TilesetEditor::importTilesetMetatiles(Tileset *tileset, bool primary) break; } + uint16_t metatileId = static_cast(metatileIdBase + i); + QString prevLabel = Tileset::getOwnedMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset); Metatile *prevMetatile = new Metatile(*tileset->metatiles.at(i)); - MetatileHistoryItem *commit = new MetatileHistoryItem(static_cast(metatileIdBase + i), - prevMetatile, new Metatile(*metatiles.at(i))); + MetatileHistoryItem *commit = new MetatileHistoryItem(metatileId, + prevMetatile, new Metatile(*metatiles.at(i)), + prevLabel, prevLabel); metatileHistory.push(commit); } @@ -1146,11 +1154,12 @@ void TilesetEditor::countTileUsage() { } void TilesetEditor::on_copyButton_metatileLabel_clicked() { - QString label = this->ui->lineEdit_metatileLabel->text(); + uint16_t metatileId = this->getSelectedMetatileId(); + QString label = Tileset::getMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset); if (label.isEmpty()) return; - Tileset * tileset = Tileset::getMetatileTileset(this->getSelectedMetatileId(), this->primaryTileset, this->secondaryTileset); + Tileset * tileset = Tileset::getMetatileLabelTileset(metatileId, this->primaryTileset, this->secondaryTileset); if (tileset) - label.prepend("METATILE_" + QString(tileset->name).replace("gTileset_", "") + "_"); + label.prepend(tileset->getMetatileLabelPrefix()); QGuiApplication::clipboard()->setText(label); QToolTip::showText(this->ui->copyButton_metatileLabel->mapToGlobal(QPoint(0, 0)), "Copied!"); }