From 514ecb29079066d248aaec9f6b9c07ee7059a469 Mon Sep 17 00:00:00 2001
From: Marcus Huderle <huderlem@gmail.com>
Date: Mon, 9 Jul 2018 17:40:28 -0500
Subject: [PATCH] Add map resizing functionality

---
 mainwindow.cpp | 42 ++++++++++++++++++++++++++++++++++++------
 map.cpp        | 24 ++++++++++++++++++++++++
 map.h          |  1 +
 3 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/mainwindow.cpp b/mainwindow.cpp
index 378c7d71..e9e97dd1 100755
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -851,21 +851,51 @@ void MainWindow::on_pushButton_clicked()
 
     QSpinBox *widthSpinBox = new QSpinBox();
     QSpinBox *heightSpinBox = new QSpinBox();
-    widthSpinBox->setValue(editor->map->getWidth());
-    heightSpinBox->setValue(editor->map->getHeight());
     widthSpinBox->setMinimum(1);
     heightSpinBox->setMinimum(1);
-    widthSpinBox->setMaximum(255);
-    heightSpinBox->setMaximum(255);
+    // See below for explanation of maximum map dimensions
+    widthSpinBox->setMaximum(0x1E7);
+    heightSpinBox->setMaximum(0x1D1);
+    widthSpinBox->setValue(editor->map->getWidth());
+    heightSpinBox->setValue(editor->map->getHeight());
     form.addRow(new QLabel("Width"), widthSpinBox);
     form.addRow(new QLabel("Height"), heightSpinBox);
 
+    QLabel *errorLabel = new QLabel();
+    QPalette errorPalette;
+    errorPalette.setColor(QPalette::WindowText, Qt::red);
+    errorLabel->setPalette(errorPalette);
+    errorLabel->setVisible(false);
+
     QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
     form.addRow(&buttonBox);
-    connect(&buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
+    connect(&buttonBox, &QDialogButtonBox::accepted, [&dialog, &widthSpinBox, &heightSpinBox, &errorLabel](){
+        // Ensure width and height are an acceptable size.
+        // The maximum number of metatiles in a map is the following:
+        //    max = (width + 15) * (height + 14)
+        // This limit can be found in fieldmap.c in pokeruby/pokeemerald.
+        int realWidth = widthSpinBox->value() + 15;
+        int realHeight = heightSpinBox->value() + 14;
+        int numMetatiles = realWidth * realHeight;
+        if (numMetatiles <= 0x2800) {
+            dialog.accept();
+        } else {
+            QString errorText = QString("Error: The specified width and height are too large.\n"
+                    "The maximum width and height is the following: (width + 15) * (height + 14) <= 10240\n"
+                    "The specified width and height was: (%1 + 15) * (%2 + 14) = %3")
+                        .arg(widthSpinBox->value())
+                        .arg(heightSpinBox->value())
+                        .arg(numMetatiles);
+            errorLabel->setText(errorText);
+            errorLabel->setVisible(true);
+        }
+    });
     connect(&buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
 
+    form.addRow(errorLabel);
+
     if (dialog.exec() == QDialog::Accepted) {
-        qDebug() << "Change width";
+        editor->map->setDimensions(widthSpinBox->value(), heightSpinBox->value());
+        setMap(editor->map->name);
     }
 }
diff --git a/map.cpp b/map.cpp
index 2c1189c3..858bf156 100755
--- a/map.cpp
+++ b/map.cpp
@@ -427,6 +427,30 @@ QPixmap Map::renderMetatiles() {
     return QPixmap::fromImage(image);
 }
 
+void Map::setDimensions(int newWidth, int newHeight) {
+    int oldWidth = getWidth();
+    int oldHeight = getHeight();
+
+    Blockdata* newBlockData = new Blockdata;
+
+    for (int y = 0; y < newHeight; y++)
+    for (int x = 0; x < newWidth; x++) {
+        if (x < oldWidth && y < oldHeight) {
+            int index = y * oldWidth + x;
+            newBlockData->addBlock(layout->blockdata->blocks->value(index));
+        } else {
+            newBlockData->addBlock(0);
+        }
+    }
+
+    layout->blockdata->copyFrom(newBlockData);
+    layout->width = QString::number(newWidth);
+    layout->height = QString::number(newHeight);
+    commit();
+
+    emit mapChanged(this);
+}
+
 Block* Map::getBlock(int x, int y) {
     if (layout->blockdata && layout->blockdata->blocks) {
         if (x >= 0 && x < getWidth())
diff --git a/map.h b/map.h
index a98359a1..450e39ce 100755
--- a/map.h
+++ b/map.h
@@ -194,6 +194,7 @@ public:
 
     QList<Connection*> connections;
     QPixmap renderConnection(Connection);
+    void setDimensions(int, int);
 
     QPixmap renderBorder();
     void cacheBorder();