diff --git a/CHANGELOG.md b/CHANGELOG.md
index a0c38a18..f3124e92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,20 @@ and this project somewhat adheres to [Semantic Versioning](https://semver.org/sp
The **"Breaking Changes"** listed below are changes that have been made in the decompilation projects (e.g. pokeemerald), which porymap requires in order to work properly. If porymap is used on a project that is not up-to-date with the breaking changes, then porymap will likely break or behave improperly.
## Unreleased
-Nothing, yet.
+### Breaking Changes
+- If you are using pokeemerald or pokeruby, there were changes made in [pokeemerald/#1010](https://github.com/pret/pokeemerald/pull/1010) and [pokeruby/#776](https://github.com/pret/pokeruby/pull/776) that you will need to integrate in order to use this version of porymap.
+
+### Added
+- Support for [pokefirered](https://github.com/pret/pokefirered). Kanto fans rejoice! At long last porymap supports the FRLG decompilation project.
+- Add ability to export map stitches with `File -> Export Map Stitch Image...`.
+
+### Changed
+- Porymap now saves map and encounter json data in an order consistent with the upstream repos. This will provide more comprehensible diffs, among other things.
+
+### Fixed
+- Fix bug where pressing TAB key did not navigate through widgets in the wild encounter tables.
+- Fix bug that allowed selecting an invalid metatile in the metatile selector.
+
## [3.0.1] - 2020-03-04
### Fixed
diff --git a/README.md b/README.md
index 06a3a3bf..f6f7a8b8 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
# porymap
-A map editor for the generation 3 disassembly projects using Qt.
+A map editor for the generation 3 decompilation projects using Qt.
-Currently supports [pokeruby][pokeruby] and [pokeemerald][pokeemerald].
+Currently supports [pokeruby][pokeruby], [pokeemerald][pokeemerald], and [pokefirered][pokefirered].
Documentation: https://huderlem.github.io/porymap/
@@ -10,5 +10,6 @@ View the [Changelog][changelog] to see what's new, and download the latest versi
[pokeruby]: https://github.com/pret/pokeruby
[pokeemerald]: https://github.com/pret/pokeemerald
+[pokefirered]: https://github.com/pret/pokefirered
[changelog]: https://github.com/huderlem/porymap/blob/master/CHANGELOG.md
[releases]: https://github.com/huderlem/porymap/releases
diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui
index f08bde20..56fc6e0e 100644
--- a/forms/mainwindow.ui
+++ b/forms/mainwindow.ui
@@ -2892,6 +2892,7 @@
+
@@ -3210,6 +3211,10 @@
Use PoryScript
+
+
+ Export Map Stitch Image...
+
diff --git a/include/editor.h b/include/editor.h
index 52c3fdc7..31279095 100644
--- a/include/editor.h
+++ b/include/editor.h
@@ -137,6 +137,8 @@ public:
void objectsView_onMouseMove(QMouseEvent *event);
void objectsView_onMouseRelease(QMouseEvent *event);
+ int getBorderDrawDistance(int dimension);
+
private:
void setConnectionItemsVisible(bool);
void setBorderItemsVisible(bool, qreal = 1);
@@ -153,7 +155,6 @@ private:
void updateMirroredConnectionMap(MapConnection*, QString);
void updateMirroredConnection(MapConnection*, QString, QString, bool isDelete = false);
void updateEncounterFields(EncounterFields newFields);
- int getBorderDrawDistance(int dimension);
Event* createNewObjectEvent();
Event* createNewWarpEvent();
Event* createNewHealLocationEvent();
diff --git a/include/lib/orderedjson.h b/include/lib/orderedjson.h
index 645b4336..54452314 100644
--- a/include/lib/orderedjson.h
+++ b/include/lib/orderedjson.h
@@ -62,6 +62,10 @@
#include
#include
+#include
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 1)
+ #include "qstringhash.h"
+#endif
#include "orderedmap.h"
#ifdef _MSC_VER
diff --git a/include/lib/orderedmap.h b/include/lib/orderedmap.h
index df94d861..40fe08b8 100644
--- a/include/lib/orderedmap.h
+++ b/include/lib/orderedmap.h
@@ -1640,7 +1640,7 @@ private:
* the erased element and all the ones after the erased element (including end()).
* Otherwise all the iterators are invalidated if an erase occurs.
*/
-template,
class KeyEqual = std::equal_to,
@@ -2031,7 +2031,7 @@ public:
- T& operator[](const Key& key) { return m_ht[key]; }
+ T& operator[](const Key& key) { return m_ht[key]; }
T& operator[](Key&& key) { return m_ht[std::move(key)]; }
@@ -2042,7 +2042,7 @@ public:
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
* as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
*/
- size_type count(const Key& key, std::size_t precalculated_hash) const {
+ size_type count(const Key& key, std::size_t precalculated_hash) const {
return m_ht.count(key, precalculated_hash);
}
@@ -2079,7 +2079,7 @@ public:
/**
* @copydoc find(const Key& key, std::size_t precalculated_hash)
*/
- const_iterator find(const Key& key, std::size_t precalculated_hash) const {
+ const_iterator find(const Key& key, std::size_t precalculated_hash) const {
return m_ht.find(key, precalculated_hash);
}
@@ -2124,7 +2124,7 @@ public:
* Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
* as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
*/
- std::pair equal_range(const Key& key, std::size_t precalculated_hash) {
+ std::pair equal_range(const Key& key, std::size_t precalculated_hash) {
return m_ht.equal_range(key, precalculated_hash);
}
@@ -2133,7 +2133,7 @@ public:
/**
* @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
*/
- std::pair equal_range(const Key& key, std::size_t precalculated_hash) const {
+ std::pair equal_range(const Key& key, std::size_t precalculated_hash) const {
return m_ht.equal_range(key, precalculated_hash);
}
diff --git a/include/lib/qstringhash.h b/include/lib/qstringhash.h
new file mode 100644
index 00000000..10947d6f
--- /dev/null
+++ b/include/lib/qstringhash.h
@@ -0,0 +1,19 @@
+#ifndef QSTRINGHASH_H
+#define QSTRINGHASH_H
+
+#include
+#include
+#include
+
+// This is a custom hash function for QString so it can be used as
+// a key in a std::hash structure. Qt 5.14 added this function, so
+// this file should only be included in earlier versions.
+namespace std {
+ template<> struct hash {
+ std::size_t operator()(const QString& s) const noexcept {
+ return static_cast(qHash(s));
+ }
+ };
+}
+
+#endif // QSTRINGHASH_H
diff --git a/include/mainwindow.h b/include/mainwindow.h
index 3cd89daa..15182ec7 100644
--- a/include/mainwindow.h
+++ b/include/mainwindow.h
@@ -117,6 +117,7 @@ private slots:
void currentMetatilesSelectionChanged();
void on_action_Export_Map_Image_triggered();
+ void on_actionExport_Stitched_Map_Image_triggered();
void on_comboBox_ConnectionDirection_currentIndexChanged(const QString &arg1);
void on_spinBox_ConnectionOffset_valueChanged(int offset);
@@ -228,6 +229,7 @@ private:
void closeSupplementaryWindows();
bool isProjectOpen();
+ void showExportMapImageWindow(bool stitchMode);
};
enum MapListUserRoles {
diff --git a/include/project.h b/include/project.h
index 5f432b81..e0e0d859 100644
--- a/include/project.h
+++ b/include/project.h
@@ -106,7 +106,8 @@ public:
QString readMapLocation(QString map_name);
bool readWildMonData();
- QMap> wildMonData;
+ tsl::ordered_map> wildMonData;
+
QVector wildMonFields;
QVector encounterGroupLabels;
QVector extraEncounterGroups;
diff --git a/include/ui/mapimageexporter.h b/include/ui/mapimageexporter.h
index a6772ed1..0dedb204 100644
--- a/include/ui/mapimageexporter.h
+++ b/include/ui/mapimageexporter.h
@@ -15,7 +15,7 @@ class MapImageExporter : public QDialog
Q_OBJECT
public:
- explicit MapImageExporter(QWidget *parent, Editor *editor);
+ explicit MapImageExporter(QWidget *parent, Editor *editor, bool stitchMode);
~MapImageExporter();
private:
@@ -39,9 +39,12 @@ private:
bool showGrid = false;
bool showBorder = false;
bool showCollision = false;
+ bool stitchMode = false;
void updatePreview();
void saveImage();
+ QPixmap getStitchedImage(QProgressDialog *progress, bool includeBorder);
+ QPixmap getFormattedMapPixmap(Map *map, bool ignoreBorder);
private slots:
void on_checkBox_Objects_stateChanged(int state);
diff --git a/porymap.pro b/porymap.pro
index 0bfb5550..5e686c78 100644
--- a/porymap.pro
+++ b/porymap.pro
@@ -10,7 +10,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = porymap
TEMPLATE = app
-RC_ICONS = resources/icons/porymap-icon-1.ico
+RC_ICONS = resources/icons/porymap-icon-2.ico
ICON = resources/icons/porymap.icns
QMAKE_CXXFLAGS += -std=c++11 -Wall
@@ -134,7 +134,8 @@ HEADERS += include/core/block.h \
include/project.h \
include/settings.h \
include/log.h \
- include/ui/newtilesetdialog.h
+ include/ui/newtilesetdialog.h \
+ include/lib/qstringhash.h
FORMS += forms/mainwindow.ui \
forms/eventpropertiesframe.ui \
diff --git a/resources/icons/porymap-icon-2.ico b/resources/icons/porymap-icon-2.ico
new file mode 100644
index 00000000..72f52834
Binary files /dev/null and b/resources/icons/porymap-icon-2.ico differ
diff --git a/resources/icons/porymap.icns b/resources/icons/porymap.icns
index ef3b77fb..a8a8bd4a 100644
Binary files a/resources/icons/porymap.icns and b/resources/icons/porymap.icns differ
diff --git a/src/core/regionmap.cpp b/src/core/regionmap.cpp
index c44339d0..d2025817 100644
--- a/src/core/regionmap.cpp
+++ b/src/core/regionmap.cpp
@@ -195,14 +195,7 @@ bool RegionMap::readLayout() {
map_squares[i].has_map = true;
}
map_squares[i].mapsec = secname;
- if (!mapSecToMapEntry.contains(secname)) {
- continue;
- }
- QString name = mapSecToMapEntry.value(secname).name;
- if (!sMapNamesMap.contains(name)) {
- continue;
- }
- map_squares[i].map_name = sMapNamesMap.value(name);
+ map_squares[i].map_name = sMapNamesMap.value(mapSecToMapEntry.value(secname).name);
map_squares[i].x = x;
map_squares[i].y = y;
}
diff --git a/src/editor.cpp b/src/editor.cpp
index 5f84350f..40f2f404 100644
--- a/src/editor.cpp
+++ b/src/editor.cpp
@@ -189,17 +189,20 @@ void Editor::displayWildMonTables() {
return;
}
- labelCombo->addItems(project->wildMonData[map->constantName].keys());
- labelCombo->setCurrentText(project->wildMonData[map->constantName].firstKey());
+ for (auto groupPair : project->wildMonData[map->constantName])
+ labelCombo->addItem(groupPair.first);
- for (int labelIndex = 0; labelIndex < project->wildMonData[map->constantName].keys().size(); labelIndex++) {
+ labelCombo->setCurrentText(labelCombo->itemText(0));
- QString label = project->wildMonData.value(map->constantName).keys().at(labelIndex);
+ int labelIndex = 0;
+ for (auto labelPair : project->wildMonData[map->constantName]) {
- WildPokemonHeader header = project->wildMonData.value(map->constantName).value(label);
+ QString label = labelPair.first;
+
+ WildPokemonHeader header = project->wildMonData[map->constantName][label];
MonTabWidget *tabWidget = new MonTabWidget(this);
- stack->insertWidget(labelIndex, tabWidget);
+ stack->insertWidget(labelIndex++, tabWidget);
int tabIndex = 0;
for (EncounterField monField : project->wildMonFields) {
@@ -569,7 +572,7 @@ void Editor::saveEncounterTabData() {
if (!stack->count()) return;
- QMap &encounterMap = project->wildMonData[map->constantName];
+ tsl::ordered_map &encounterMap = project->wildMonData[map->constantName];
for (int groupIndex = 0; groupIndex < stack->count(); groupIndex++) {
MonTabWidget *tabWidget = static_cast(stack->widget(groupIndex));
@@ -604,8 +607,10 @@ void Editor::updateEncounterFields(EncounterFields newFields) {
if (oldFieldName == newFieldName) {
fieldDeleted = false;
if (oldField.encounterRates.size() != newField.encounterRates.size()) {
- for (QString map : project->wildMonData.keys()) {
- for (QString groupName : project->wildMonData.value(map).keys()) {
+ for (auto mapPair : project->wildMonData) {
+ QString map = mapPair.first;
+ for (auto groupNamePair : project->wildMonData[map]) {
+ QString groupName = groupNamePair.first;
WildPokemonHeader &monHeader = project->wildMonData[map][groupName];
for (QString fieldName : monHeader.wildMons.keys()) {
if (fieldName == oldFieldName) {
@@ -618,8 +623,10 @@ void Editor::updateEncounterFields(EncounterFields newFields) {
}
}
if (fieldDeleted) {
- for (QString map : project->wildMonData.keys()) {
- for (QString groupName : project->wildMonData.value(map).keys()) {
+ for (auto mapPair : project->wildMonData) {
+ QString map = mapPair.first;
+ for (auto groupNamePair : project->wildMonData[map]) {
+ QString groupName = groupNamePair.first;
WildPokemonHeader &monHeader = project->wildMonData[map][groupName];
for (QString fieldName : monHeader.wildMons.keys()) {
if (fieldName == oldFieldName) {
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 2643004f..0ffa3381 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
@@ -2137,13 +2138,21 @@ void MainWindow::onTilesetsSaved(QString primaryTilesetLabel, QString secondaryT
this->editor->updateSecondaryTileset(secondaryTilesetLabel, true);
}
-void MainWindow::on_action_Export_Map_Image_triggered()
-{
- if (!this->mapImageExporter) {
- this->mapImageExporter = new MapImageExporter(this, this->editor);
- connect(this->mapImageExporter, &QObject::destroyed, [=](QObject *) { this->mapImageExporter = nullptr; });
- this->mapImageExporter->setAttribute(Qt::WA_DeleteOnClose);
- }
+void MainWindow::on_action_Export_Map_Image_triggered() {
+ showExportMapImageWindow(false);
+}
+
+void MainWindow::on_actionExport_Stitched_Map_Image_triggered() {
+ showExportMapImageWindow(true);
+}
+
+void MainWindow::showExportMapImageWindow(bool stitchMode) {
+ if (this->mapImageExporter)
+ delete this->mapImageExporter;
+
+ this->mapImageExporter = new MapImageExporter(this, this->editor, stitchMode);
+ connect(this->mapImageExporter, &QObject::destroyed, [=](QObject *) { this->mapImageExporter = nullptr; });
+ this->mapImageExporter->setAttribute(Qt::WA_DeleteOnClose);
if (!this->mapImageExporter->isVisible()) {
this->mapImageExporter->show();
diff --git a/src/project.cpp b/src/project.cpp
index 2a69469e..e19f2f33 100644
--- a/src/project.cpp
+++ b/src/project.cpp
@@ -806,13 +806,15 @@ void Project::saveWildMonData() {
monHeadersObject["fields"] = fieldsInfoArray;
OrderedJson::array encountersArray;
- for (QString key : wildMonData.keys()) {
- for (QString groupLabel : wildMonData.value(key).keys()) {
+ for (auto keyPair : wildMonData) {
+ QString key = keyPair.first;
+ for (auto grouplLabelPair : wildMonData[key]) {
+ QString groupLabel = grouplLabelPair.first;
OrderedJson::object encounterObject;
encounterObject["map"] = key;
encounterObject["base_label"] = groupLabel;
- WildPokemonHeader encounterHeader = wildMonData.value(key).value(groupLabel);
+ WildPokemonHeader encounterHeader = wildMonData[key][groupLabel];
for (QString fieldName : encounterHeader.wildMons.keys()) {
OrderedJson::object fieldObject;
WildMonInfo monInfo = encounterHeader.wildMons.value(fieldName);
@@ -1843,7 +1845,7 @@ bool Project::readWildMonData() {
}
}
}
- wildMonData[mapConstant].insert(encounter.toObject().value("base_label").toString(), header);
+ wildMonData[mapConstant].insert({encounter.toObject().value("base_label").toString(), header});
encounterGroupLabels.append(encounter.toObject().value("base_label").toString());
}
}
diff --git a/src/ui/mapimageexporter.cpp b/src/ui/mapimageexporter.cpp
index 2cdd45e7..bb4878bd 100644
--- a/src/ui/mapimageexporter.cpp
+++ b/src/ui/mapimageexporter.cpp
@@ -7,13 +7,19 @@
#include
#include
-MapImageExporter::MapImageExporter(QWidget *parent_, Editor *editor_) :
+#define STITCH_MODE_BORDER_DISTANCE 2
+
+MapImageExporter::MapImageExporter(QWidget *parent_, Editor *editor_, bool stitchMode) :
QDialog(parent_),
ui(new Ui::MapImageExporter)
{
ui->setupUi(this);
this->map = editor_->map;
this->editor = editor_;
+ this->stitchMode = stitchMode;
+
+ this->setWindowTitle(this->stitchMode ? "Export Map Stitch Image" : "Export Map Image");
+ this->ui->groupBox_Connections->setVisible(!this->stitchMode);
this->ui->comboBox_MapSelection->addItems(*editor->project->mapNames);
this->ui->comboBox_MapSelection->setCurrentText(map->name);
@@ -28,32 +34,192 @@ MapImageExporter::~MapImageExporter() {
}
void MapImageExporter::saveImage() {
- QString defaultFilepath = QString("%1/%2.png").arg(editor->project->root).arg(map->name);
- QString filepath = QFileDialog::getSaveFileName(this, "Export Map Image", defaultFilepath,
+ QString title = this->stitchMode ? "Export Map Stitch Image" : "Export Map Image";
+ QString defaultFilename = this->stitchMode ? QString("Stitch_From_%1").arg(map->name) : map->name;
+ QString defaultFilepath = QString("%1/%2.png").arg(editor->project->root).arg(defaultFilename);
+ QString filepath = QFileDialog::getSaveFileName(this, title, defaultFilepath,
"Image Files (*.png *.jpg *.bmp)");
if (!filepath.isEmpty()) {
- this->preview.save(filepath);
+ if (this->stitchMode) {
+ QProgressDialog progress("Building map stitch...", "Cancel", 0, 1, this);
+ progress.setAutoClose(true);
+ progress.setWindowModality(Qt::WindowModal);
+ progress.setModal(true);
+ QPixmap pixmap = this->getStitchedImage(&progress, this->showBorder);
+ if (progress.wasCanceled()) {
+ progress.close();
+ return;
+ }
+ pixmap.save(filepath);
+ progress.close();
+ } else {
+ this->preview.save(filepath);
+ }
this->close();
}
}
+struct StitchedMap {
+ int x;
+ int y;
+ Map* map;
+};
+
+QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress, bool includeBorder) {
+ // Do a breadth-first search to gather a collection of
+ // all reachable maps with their relative offsets.
+ QSet visited;
+ QList stitchedMaps;
+ QList unvisited;
+ unvisited.append(StitchedMap{0, 0, this->editor->map});
+
+ progress->setLabelText("Gathering stitched maps...");
+ while (!unvisited.isEmpty()) {
+ if (progress->wasCanceled()) {
+ return QPixmap();
+ }
+ progress->setMaximum(visited.size() + unvisited.size());
+ progress->setValue(visited.size());
+
+ StitchedMap cur = unvisited.takeFirst();
+ if (visited.contains(cur.map->name))
+ continue;
+ visited.insert(cur.map->name);
+ stitchedMaps.append(cur);
+
+ for (MapConnection *connection : cur.map->connections) {
+ if (connection->direction == "dive" || connection->direction == "emerge")
+ continue;
+ int x = cur.x;
+ int y = cur.y;
+ int offset = connection->offset.toInt(nullptr, 0);
+ Map *connectionMap = this->editor->project->loadMap(connection->map_name);
+ if (connection->direction == "up") {
+ x += offset;
+ y -= connectionMap->getHeight();
+ } else if (connection->direction == "down") {
+ x += offset;
+ y += cur.map->getHeight();
+ } else if (connection->direction == "left") {
+ x -= connectionMap->getWidth();
+ y += offset;
+ } else if (connection->direction == "right") {
+ x += cur.map->getWidth();
+ y += offset;
+ }
+ unvisited.append(StitchedMap{x, y, connectionMap});
+ }
+ }
+
+ // Determine the overall dimensions of the stitched maps.
+ int maxX = INT_MIN;
+ int minX = INT_MAX;
+ int maxY = INT_MIN;
+ int minY = INT_MAX;
+ for (StitchedMap map : stitchedMaps) {
+ int left = map.x;
+ int right = map.x + map.map->getWidth();
+ int top = map.y;
+ int bottom = map.y + map.map->getHeight();
+ if (left < minX)
+ minX = left;
+ if (right > maxX)
+ maxX = right;
+ if (top < minY)
+ minY = top;
+ if (bottom > maxY)
+ maxY = bottom;
+ }
+
+ if (includeBorder) {
+ minX -= STITCH_MODE_BORDER_DISTANCE;
+ maxX += STITCH_MODE_BORDER_DISTANCE;
+ minY -= STITCH_MODE_BORDER_DISTANCE;
+ maxY += STITCH_MODE_BORDER_DISTANCE;
+ }
+
+ // Draw the maps on the full canvas, while taking
+ // their respective offsets into account.
+ progress->setLabelText("Drawing stitched maps...");
+ progress->setValue(0);
+ progress->setMaximum(stitchedMaps.size());
+ int numDrawn = 0;
+ QPixmap stitchedPixmap((maxX - minX) * 16, (maxY - minY) * 16);
+ QPainter painter(&stitchedPixmap);
+ for (StitchedMap map : stitchedMaps) {
+ if (progress->wasCanceled()) {
+ return QPixmap();
+ }
+ progress->setValue(numDrawn);
+ numDrawn++;
+
+ int pixelX = (map.x - minX) * 16;
+ int pixelY = (map.y - minY) * 16;
+ if (includeBorder) {
+ pixelX -= STITCH_MODE_BORDER_DISTANCE * 16;
+ pixelY -= STITCH_MODE_BORDER_DISTANCE * 16;
+ }
+ QPixmap pixmap = this->getFormattedMapPixmap(map.map, false);
+ painter.drawPixmap(pixelX, pixelY, pixmap);
+ }
+
+ // When including the borders, we simply draw all the maps again
+ // without their borders, since the first pass results in maps
+ // being occluded by other map borders.
+ if (includeBorder) {
+ progress->setLabelText("Drawing stitched maps without borders...");
+ progress->setValue(0);
+ progress->setMaximum(stitchedMaps.size());
+ numDrawn = 0;
+ for (StitchedMap map : stitchedMaps) {
+ if (progress->wasCanceled()) {
+ return QPixmap();
+ }
+ progress->setValue(numDrawn);
+ numDrawn++;
+
+ int pixelX = (map.x - minX) * 16;
+ int pixelY = (map.y - minY) * 16;
+ QPixmap pixmapWithoutBorders = this->getFormattedMapPixmap(map.map, true);
+ painter.drawPixmap(pixelX, pixelY, pixmapWithoutBorders);
+ }
+ }
+
+ return stitchedPixmap;
+}
+
void MapImageExporter::updatePreview() {
if (scene) {
delete scene;
scene = nullptr;
}
+
+ preview = getFormattedMapPixmap(this->map, false);
scene = new QGraphicsScene;
+ scene->addPixmap(preview);
+ this->scene->setSceneRect(this->scene->itemsBoundingRect());
+
+ this->ui->graphicsView_Preview->setScene(scene);
+ this->ui->graphicsView_Preview->setFixedSize(scene->itemsBoundingRect().width() + 2,
+ scene->itemsBoundingRect().height() + 2);
+}
+
+QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
+ QPixmap pixmap;
// draw background layer / base image
+ map->render(true);
if (showCollision) {
- preview = map->collision_pixmap;
+ map->renderCollision(editor->collisionOpacity, true);
+ pixmap = map->collision_pixmap;
} else {
- preview = map->pixmap;
+ pixmap = map->pixmap;
}
// draw events
- QPainter eventPainter(&preview);
+ QPainter eventPainter(&pixmap);
QList events = map->getAllEvents();
+ editor->project->loadEventPixmaps(events);
for (Event *event : events) {
QString group = event->get("event_group_type");
if ((showObjects && group == "object_event_group")
@@ -69,31 +235,40 @@ void MapImageExporter::updatePreview() {
// note: this will break when allowing map to be selected from drop down maybe
int borderHeight = 0, borderWidth = 0;
bool forceDrawBorder = showUpConnections || showDownConnections || showLeftConnections || showRightConnections;
- if (showBorder || forceDrawBorder) {
- borderHeight = BORDER_DISTANCE * 16, borderWidth = BORDER_DISTANCE * 16;
- QPixmap newPreview = QPixmap(map->pixmap.width() + borderWidth * 2, map->pixmap.height() + borderHeight * 2);
- QPainter borderPainter(&newPreview);
- for (auto borderItem : editor->borderItems) {
- borderPainter.drawImage(QPoint(borderItem->x() + borderWidth, borderItem->y() + borderHeight),
- borderItem->pixmap().toImage());
+ if (!ignoreBorder && (showBorder || forceDrawBorder)) {
+ int borderDistance = this->stitchMode ? STITCH_MODE_BORDER_DISTANCE : BORDER_DISTANCE;
+ map->renderBorder();
+ int borderHorzDist = editor->getBorderDrawDistance(map->getBorderWidth());
+ int borderVertDist = editor->getBorderDrawDistance(map->getBorderHeight());
+ borderWidth = borderDistance * 16;
+ borderHeight = borderDistance * 16;
+ QPixmap newPixmap = QPixmap(map->pixmap.width() + borderWidth * 2, map->pixmap.height() + borderHeight * 2);
+ QPainter borderPainter(&newPixmap);
+ for (int y = borderDistance - borderVertDist; y < map->getHeight() + borderVertDist * 2; y += map->getBorderHeight()) {
+ for (int x = borderDistance - borderHorzDist; x < map->getWidth() + borderHorzDist * 2; x += map->getBorderWidth()) {
+ borderPainter.drawPixmap(x * 16, y * 16, map->layout->border_pixmap);
+ }
}
- borderPainter.drawImage(QPoint(borderWidth, borderHeight), preview.toImage());
+
+ borderPainter.drawImage(borderWidth, borderHeight, pixmap.toImage());
borderPainter.end();
- preview = newPreview;
+ pixmap = newPixmap;
}
- // if showing connections, draw on outside of image
- QPainter connectionPainter(&preview);
- for (auto connectionItem : editor->connection_edit_items) {
- QString direction = connectionItem->connection->direction;
- if ((showUpConnections && direction == "up")
- || (showDownConnections && direction == "down")
- || (showLeftConnections && direction == "left")
- || (showRightConnections && direction == "right"))
- connectionPainter.drawImage(connectionItem->initialX + borderWidth, connectionItem->initialY + borderHeight,
- connectionItem->basePixmap.toImage());
+ if (!this->stitchMode) {
+ // if showing connections, draw on outside of image
+ QPainter connectionPainter(&pixmap);
+ for (auto connectionItem : editor->connection_edit_items) {
+ QString direction = connectionItem->connection->direction;
+ if ((showUpConnections && direction == "up")
+ || (showDownConnections && direction == "down")
+ || (showLeftConnections && direction == "left")
+ || (showRightConnections && direction == "right"))
+ connectionPainter.drawImage(connectionItem->initialX + borderWidth, connectionItem->initialY + borderHeight,
+ connectionItem->basePixmap.toImage());
+ }
+ connectionPainter.end();
}
- connectionPainter.end();
// draw grid directly onto the pixmap
// since the last grid lines are outside of the pixmap, add a pixel to the bottom and right
@@ -102,24 +277,20 @@ void MapImageExporter::updatePreview() {
if (borderHeight) addY = 0;
if (borderWidth) addX = 0;
- QPixmap newPreview = QPixmap(preview.width() + addX, preview.height() + addY);
- QPainter gridPainter(&newPreview);
- gridPainter.drawImage(QPoint(0, 0), preview.toImage());
- for (auto lineItem : editor->gridLines) {
- QPointF addPos(borderWidth, borderHeight);
- gridPainter.drawLine(lineItem->line().p1() + addPos, lineItem->line().p2() + addPos);
+ QPixmap newPixmap= QPixmap(pixmap.width() + addX, pixmap.height() + addY);
+ QPainter gridPainter(&newPixmap);
+ gridPainter.drawImage(QPoint(0, 0), pixmap.toImage());
+ for (int x = 0; x < newPixmap.width(); x += 16) {
+ gridPainter.drawLine(x, 0, x, newPixmap.height());
+ }
+ for (int y = 0; y < newPixmap.height(); y += 16) {
+ gridPainter.drawLine(0, y, newPixmap.width(), y);
}
gridPainter.end();
- preview = newPreview;
+ pixmap = newPixmap;
}
- scene->addPixmap(preview);
-
- this->scene->setSceneRect(this->scene->itemsBoundingRect());
-
- this->ui->graphicsView_Preview->setScene(scene);
- this->ui->graphicsView_Preview->setFixedSize(scene->itemsBoundingRect().width() + 2,
- scene->itemsBoundingRect().height() + 2);
+ return pixmap;
}
void MapImageExporter::on_checkBox_Elevation_stateChanged(int state) {
diff --git a/src/ui/newtilesetdialog.cpp b/src/ui/newtilesetdialog.cpp
index a2d5f3f4..0639fab3 100644
--- a/src/ui/newtilesetdialog.cpp
+++ b/src/ui/newtilesetdialog.cpp
@@ -11,7 +11,7 @@ NewTilesetDialog::NewTilesetDialog(Project* project, QWidget *parent) :
this->setFixedSize(this->width(), this->height());
this->project = project;
//only allow characters valid for a symbol
- QRegExp expression("[-_.A-Za-z0-9]+$");
+ QRegExp expression("[_A-Za-z0-9]+$");
QRegExpValidator *validator = new QRegExpValidator(expression);
this->ui->nameLineEdit->setValidator(validator);