Browse Source

Merge pull request #55 from huderlem/resize

Map resizing and improved floodfill
yenatch 6 years ago
parent
commit
52679eb53f
No account linked to committer's email address
7 changed files with 350 additions and 90 deletions
  1. 160
    22
      editor.cpp
  2. 2
    2
      editor.h
  3. 86
    10
      mainwindow.cpp
  4. 6
    0
      mainwindow.h
  5. 19
    2
      mainwindow.ui
  6. 62
    51
      map.cpp
  7. 15
    3
      map.h

+ 160
- 22
editor.cpp View File

@@ -26,13 +26,15 @@ void Editor::save() {
26 26
 
27 27
 void Editor::undo() {
28 28
     if (current_view) {
29
-        ((MapPixmapItem*)current_view)->undo();
29
+        map->undo();
30
+        map_item->draw();
30 31
     }
31 32
 }
32 33
 
33 34
 void Editor::redo() {
34 35
     if (current_view) {
35
-        ((MapPixmapItem*)current_view)->redo();
36
+        map->redo();
37
+        map_item->draw();
36 38
     }
37 39
 }
38 40
 
@@ -58,6 +60,7 @@ void Editor::setEditingMap() {
58 60
 void Editor::setEditingCollision() {
59 61
     current_view = collision_item;
60 62
     if (collision_item) {
63
+        displayMapConnections();
61 64
         collision_item->draw();
62 65
         collision_item->setVisible(true);
63 66
         setConnectionsVisibility(true);
@@ -318,8 +321,8 @@ void Editor::setMap(QString map_name) {
318 321
     }
319 322
     if (project) {
320 323
         map = project->loadMap(map_name);
321
-        displayMap();
322 324
         selected_events->clear();
325
+        displayMap();
323 326
         updateSelectedEvents();
324 327
     }
325 328
 }
@@ -879,9 +882,6 @@ void MetatilesPixmapItem::updateSelection(QPointF pos, Qt::MouseButton button) {
879 882
         map->paint_tile_index = baseTileY * 8 + baseTileX;
880 883
         map->paint_tile_width = abs(map->paint_metatile_initial_x - x) + 1;
881 884
         map->paint_tile_height = abs(map->paint_metatile_initial_y - y) + 1;
882
-        map->smart_paths_enabled = button == Qt::RightButton
883
-                                && map->paint_tile_width == 3
884
-                                && map->paint_tile_height == 3;
885 885
         emit map->paintTileChanged(map);
886 886
     }
887 887
 }
@@ -1029,7 +1029,7 @@ void MapPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
1029 1029
         int x = (int)(pos.x()) / 16;
1030 1030
         int y = (int)(pos.y()) / 16;
1031 1031
 
1032
-        if (map->smart_paths_enabled) {
1032
+        if (map->smart_paths_enabled && map->paint_tile_width == 3 && map->paint_tile_height == 3) {
1033 1033
             paintSmartPath(x, y);
1034 1034
         } else {
1035 1035
             paintNormal(x, y);
@@ -1157,11 +1157,163 @@ void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
1157 1157
         QPointF pos = event->pos();
1158 1158
         int x = (int)(pos.x()) / 16;
1159 1159
         int y = (int)(pos.y()) / 16;
1160
-        map->floodFill(x, y, map->getSelectedBlockIndex(map->paint_tile_index));
1160
+        Block *block = map->getBlock(x, y);
1161
+        int tile = map->getSelectedBlockIndex(map->paint_tile_index);
1162
+        if (block && block->tile != tile) {
1163
+            if (map->smart_paths_enabled && map->paint_tile_width == 3 && map->paint_tile_height == 3)
1164
+                this->_floodFillSmartPath(x, y);
1165
+            else
1166
+                this->_floodFill(x, y);
1167
+        }
1168
+
1169
+        if (event->type() == QEvent::GraphicsSceneMouseRelease) {
1170
+            map->commit();
1171
+        }
1161 1172
         draw();
1162 1173
     }
1163 1174
 }
1164 1175
 
1176
+void MapPixmapItem::_floodFill(int initialX, int initialY) {
1177
+    QList<QPoint> todo;
1178
+    todo.append(QPoint(initialX, initialY));
1179
+    while (todo.length()) {
1180
+        QPoint point = todo.takeAt(0);
1181
+        int x = point.x();
1182
+        int y = point.y();
1183
+
1184
+        Block *block = map->getBlock(x, y);
1185
+        if (block == NULL) {
1186
+            continue;
1187
+        }
1188
+
1189
+        int xDiff = x - initialX;
1190
+        int yDiff = y - initialY;
1191
+        int i = xDiff % map->paint_tile_width;
1192
+        int j = yDiff % map->paint_tile_height;
1193
+        if (i < 0) i = map->paint_tile_width + i;
1194
+        if (j < 0) j = map->paint_tile_height + j;
1195
+        int tile = map->getSelectedBlockIndex(map->paint_tile_index + i + (j * 8));
1196
+        uint old_tile = block->tile;
1197
+        if (old_tile == tile) {
1198
+            continue;
1199
+        }
1200
+
1201
+        block->tile = tile;
1202
+        map->_setBlock(x, y, *block);
1203
+        if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
1204
+            todo.append(QPoint(x + 1, y));
1205
+        }
1206
+        if ((block = map->getBlock(x - 1, y)) && block->tile == old_tile) {
1207
+            todo.append(QPoint(x - 1, y));
1208
+        }
1209
+        if ((block = map->getBlock(x, y + 1)) && block->tile == old_tile) {
1210
+            todo.append(QPoint(x, y + 1));
1211
+        }
1212
+        if ((block = map->getBlock(x, y - 1)) && block->tile == old_tile) {
1213
+            todo.append(QPoint(x, y - 1));
1214
+        }
1215
+    }
1216
+}
1217
+
1218
+void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
1219
+    // Smart path should never be enabled without a 3x3 block selection.
1220
+    if (map->paint_tile_width != 3 || map->paint_tile_height != 3) return;
1221
+
1222
+    // Shift to the middle tile of the smart path selection.
1223
+    int openTile = map->paint_tile_index + 8 + 1;
1224
+
1225
+    // Flood fill the region with the open tile.
1226
+    QList<QPoint> todo;
1227
+    todo.append(QPoint(initialX, initialY));
1228
+    while (todo.length()) {
1229
+        QPoint point = todo.takeAt(0);
1230
+        int x = point.x();
1231
+        int y = point.y();
1232
+
1233
+        Block *block = map->getBlock(x, y);
1234
+        if (block == NULL) {
1235
+            continue;
1236
+        }
1237
+
1238
+        int tile = map->getSelectedBlockIndex(openTile);
1239
+        uint old_tile = block->tile;
1240
+        if (old_tile == tile) {
1241
+            continue;
1242
+        }
1243
+
1244
+        block->tile = tile;
1245
+        map->_setBlock(x, y, *block);
1246
+        if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
1247
+            todo.append(QPoint(x + 1, y));
1248
+        }
1249
+        if ((block = map->getBlock(x - 1, y)) && block->tile == old_tile) {
1250
+            todo.append(QPoint(x - 1, y));
1251
+        }
1252
+        if ((block = map->getBlock(x, y + 1)) && block->tile == old_tile) {
1253
+            todo.append(QPoint(x, y + 1));
1254
+        }
1255
+        if ((block = map->getBlock(x, y - 1)) && block->tile == old_tile) {
1256
+            todo.append(QPoint(x, y - 1));
1257
+        }
1258
+    }
1259
+
1260
+    // Go back and resolve the flood-filled edge tiles.
1261
+    // Mark tiles as visited while we go.
1262
+    bool visited[map->getWidth() * map->getHeight()];
1263
+    for (int i = 0; i < sizeof visited; i++)
1264
+        visited[i] = false;
1265
+
1266
+    todo.append(QPoint(initialX, initialY));
1267
+    while (todo.length()) {
1268
+        QPoint point = todo.takeAt(0);
1269
+        int x = point.x();
1270
+        int y = point.y();
1271
+        visited[x + y * map->getWidth()] = true;
1272
+
1273
+        Block *block = map->getBlock(x, y);
1274
+        if (block == NULL) {
1275
+            continue;
1276
+        }
1277
+
1278
+        int id = 0;
1279
+        Block *top = map->getBlock(x, y - 1);
1280
+        Block *right = map->getBlock(x + 1, y);
1281
+        Block *bottom = map->getBlock(x, y + 1);
1282
+        Block *left = map->getBlock(x - 1, y);
1283
+
1284
+        // Get marching squares value, to determine which tile to use.
1285
+        if (top && IS_SMART_PATH_TILE(top))
1286
+            id += 1;
1287
+        if (right && IS_SMART_PATH_TILE(right))
1288
+            id += 2;
1289
+        if (bottom && IS_SMART_PATH_TILE(bottom))
1290
+            id += 4;
1291
+        if (left && IS_SMART_PATH_TILE(left))
1292
+            id += 8;
1293
+
1294
+        block->tile = map->getSelectedBlockIndex(map->paint_tile_index + smartPathTable[id]);
1295
+        map->_setBlock(x, y, *block);
1296
+
1297
+        // Visit neighbors if they are smart-path tiles, and don't revisit any.
1298
+        if (!visited[x + 1 + y * map->getWidth()] && (block = map->getBlock(x + 1, y)) && IS_SMART_PATH_TILE(block)) {
1299
+            todo.append(QPoint(x + 1, y));
1300
+            visited[x + 1 + y * map->getWidth()] = true;
1301
+        }
1302
+        if (!visited[x - 1 + y * map->getWidth()] && (block = map->getBlock(x - 1, y)) && IS_SMART_PATH_TILE(block)) {
1303
+            todo.append(QPoint(x - 1, y));
1304
+            visited[x - 1 + y * map->getWidth()] = true;
1305
+        }
1306
+        if (!visited[x + (y + 1) * map->getWidth()] && (block = map->getBlock(x, y + 1)) && IS_SMART_PATH_TILE(block)) {
1307
+            todo.append(QPoint(x, y + 1));
1308
+            visited[x + (y + 1) * map->getWidth()] = true;
1309
+        }
1310
+        if (!visited[x + (y - 1) * map->getWidth()] && (block = map->getBlock(x, y - 1)) && IS_SMART_PATH_TILE(block)) {
1311
+            todo.append(QPoint(x, y - 1));
1312
+            visited[x + (y - 1) * map->getWidth()] = true;
1313
+        }
1314
+    }
1315
+}
1316
+
1165 1317
 void MapPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
1166 1318
     QPointF pos = event->pos();
1167 1319
     int x = (int)(pos.x()) / 16;
@@ -1215,20 +1367,6 @@ void MapPixmapItem::draw(bool ignoreCache) {
1215 1367
     }
1216 1368
 }
1217 1369
 
1218
-void MapPixmapItem::undo() {
1219
-    if (map) {
1220
-        map->undo();
1221
-        draw();
1222
-    }
1223
-}
1224
-
1225
-void MapPixmapItem::redo() {
1226
-    if (map) {
1227
-        map->redo();
1228
-        draw();
1229
-    }
1230
-}
1231
-
1232 1370
 void MapPixmapItem::updateCurHoveredTile(QPointF pos) {
1233 1371
     int x = ((int)pos.x()) / 16;
1234 1372
     int y = ((int)pos.y()) / 16;

+ 2
- 2
editor.h View File

@@ -250,10 +250,10 @@ public:
250 250
     QList<QPoint> selection;
251 251
     virtual void paint(QGraphicsSceneMouseEvent*);
252 252
     virtual void floodFill(QGraphicsSceneMouseEvent*);
253
+    void _floodFill(int x, int y);
254
+    void _floodFillSmartPath(int initialX, int initialY);
253 255
     virtual void pick(QGraphicsSceneMouseEvent*);
254 256
     virtual void select(QGraphicsSceneMouseEvent*);
255
-    virtual void undo();
256
-    virtual void redo();
257 257
     virtual void draw(bool ignoreCache = false);
258 258
 
259 259
 private:

+ 86
- 10
mainwindow.cpp View File

@@ -15,6 +15,8 @@
15 15
 #include <QSpacerItem>
16 16
 #include <QFont>
17 17
 #include <QScrollBar>
18
+#include <QMessageBox>
19
+#include <QDialogButtonBox>
18 20
 
19 21
 MainWindow::MainWindow(QWidget *parent) :
20 22
     QMainWindow(parent),
@@ -147,7 +149,22 @@ void MainWindow::setMap(QString map_name) {
147 149
         return;
148 150
     }
149 151
     editor->setMap(map_name);
152
+    redrawMapScene();
153
+    displayMapProperties();
154
+
155
+    setWindowTitle(map_name + " - " + editor->project->getProjectTitle() + " - pretmap");
150 156
 
157
+    connect(editor->map, SIGNAL(mapChanged(Map*)), this, SLOT(onMapChanged(Map *)));
158
+    connect(editor->map, SIGNAL(mapNeedsRedrawing(Map*)), this, SLOT(onMapNeedsRedrawing(Map *)));
159
+    connect(editor->map, SIGNAL(statusBarMessage(QString)), this, SLOT(setStatusBarMessage(QString)));
160
+
161
+    setRecentMap(map_name);
162
+    updateMapList();
163
+}
164
+
165
+void MainWindow::redrawMapScene()
166
+{
167
+    editor->displayMap();
151 168
     on_tabWidget_currentChanged(ui->tabWidget->currentIndex());
152 169
 
153 170
     ui->graphicsView_Map->setScene(editor->scene);
@@ -177,16 +194,6 @@ void MainWindow::setMap(QString map_name) {
177 194
     ui->graphicsView_Elevation->setScene(editor->scene_elevation_metatiles);
178 195
     //ui->graphicsView_Elevation->setSceneRect(editor->scene_elevation_metatiles->sceneRect());
179 196
     ui->graphicsView_Elevation->setFixedSize(editor->elevation_metatiles_item->pixmap().width() + 2, editor->elevation_metatiles_item->pixmap().height() + 2);
180
-
181
-    displayMapProperties();
182
-
183
-    setWindowTitle(map_name + " - " + editor->project->getProjectTitle() + " - pretmap");
184
-
185
-    connect(editor->map, SIGNAL(mapChanged(Map*)), this, SLOT(onMapChanged(Map *)));
186
-    connect(editor->map, SIGNAL(statusBarMessage(QString)), this, SLOT(setStatusBarMessage(QString)));
187
-
188
-    setRecentMap(map_name);
189
-    updateMapList();
190 197
 }
191 198
 
192 199
 void MainWindow::setRecentMap(QString map_name) {
@@ -785,6 +792,10 @@ void MainWindow::onMapChanged(Map *map) {
785 792
     updateMapList();
786 793
 }
787 794
 
795
+void MainWindow::onMapNeedsRedrawing(Map *map) {
796
+    redrawMapScene();
797
+}
798
+
788 799
 void MainWindow::on_action_Export_Map_Image_triggered()
789 800
 {
790 801
     QString defaultFilepath = QString("%1/%2.png").arg(editor->project->root).arg(editor->map->name);
@@ -838,3 +849,68 @@ void MainWindow::on_comboBox_SecondaryTileset_activated(const QString &tilesetLa
838 849
 {
839 850
     editor->updateSecondaryTileset(tilesetLabel);
840 851
 }
852
+
853
+void MainWindow::on_pushButton_clicked()
854
+{
855
+    QDialog dialog(this, Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
856
+    dialog.setWindowTitle("Change Map Dimensions");
857
+    dialog.setWindowModality(Qt::NonModal);
858
+
859
+    QFormLayout form(&dialog);
860
+
861
+    QSpinBox *widthSpinBox = new QSpinBox();
862
+    QSpinBox *heightSpinBox = new QSpinBox();
863
+    widthSpinBox->setMinimum(1);
864
+    heightSpinBox->setMinimum(1);
865
+    // See below for explanation of maximum map dimensions
866
+    widthSpinBox->setMaximum(0x1E7);
867
+    heightSpinBox->setMaximum(0x1D1);
868
+    widthSpinBox->setValue(editor->map->getWidth());
869
+    heightSpinBox->setValue(editor->map->getHeight());
870
+    form.addRow(new QLabel("Width"), widthSpinBox);
871
+    form.addRow(new QLabel("Height"), heightSpinBox);
872
+
873
+    QLabel *errorLabel = new QLabel();
874
+    QPalette errorPalette;
875
+    errorPalette.setColor(QPalette::WindowText, Qt::red);
876
+    errorLabel->setPalette(errorPalette);
877
+    errorLabel->setVisible(false);
878
+
879
+    QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
880
+    form.addRow(&buttonBox);
881
+    connect(&buttonBox, &QDialogButtonBox::accepted, [&dialog, &widthSpinBox, &heightSpinBox, &errorLabel](){
882
+        // Ensure width and height are an acceptable size.
883
+        // The maximum number of metatiles in a map is the following:
884
+        //    max = (width + 15) * (height + 14)
885
+        // This limit can be found in fieldmap.c in pokeruby/pokeemerald.
886
+        int realWidth = widthSpinBox->value() + 15;
887
+        int realHeight = heightSpinBox->value() + 14;
888
+        int numMetatiles = realWidth * realHeight;
889
+        if (numMetatiles <= 0x2800) {
890
+            dialog.accept();
891
+        } else {
892
+            QString errorText = QString("Error: The specified width and height are too large.\n"
893
+                    "The maximum width and height is the following: (width + 15) * (height + 14) <= 10240\n"
894
+                    "The specified width and height was: (%1 + 15) * (%2 + 14) = %3")
895
+                        .arg(widthSpinBox->value())
896
+                        .arg(heightSpinBox->value())
897
+                        .arg(numMetatiles);
898
+            errorLabel->setText(errorText);
899
+            errorLabel->setVisible(true);
900
+        }
901
+    });
902
+    connect(&buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
903
+
904
+    form.addRow(errorLabel);
905
+
906
+    if (dialog.exec() == QDialog::Accepted) {
907
+        editor->map->setDimensions(widthSpinBox->value(), heightSpinBox->value());
908
+        editor->map->commit();
909
+        onMapNeedsRedrawing(editor->map);
910
+    }
911
+}
912
+
913
+void MainWindow::on_checkBox_smartPaths_stateChanged(int selected)
914
+{
915
+    editor->map->smart_paths_enabled = selected == Qt::Checked;
916
+}

+ 6
- 0
mainwindow.h View File

@@ -38,6 +38,7 @@ private slots:
38 38
 
39 39
     void onLoadMapRequested(QString, QString);
40 40
     void onMapChanged(Map *map);
41
+    void onMapNeedsRedrawing(Map *map);
41 42
 
42 43
     void on_action_Save_triggered();
43 44
     void on_tabWidget_2_currentChanged(int index);
@@ -93,6 +94,10 @@ private slots:
93 94
 
94 95
     void on_comboBox_SecondaryTileset_activated(const QString &arg1);
95 96
 
97
+    void on_pushButton_clicked();
98
+
99
+    void on_checkBox_smartPaths_stateChanged(int selected);
100
+
96 101
 private:
97 102
     Ui::MainWindow *ui;
98 103
     QStandardItemModel *mapListModel;
@@ -100,6 +105,7 @@ private:
100 105
     Editor *editor = NULL;
101 106
     QIcon* mapIcon;
102 107
     void setMap(QString);
108
+    void redrawMapScene();
103 109
     void loadDataStructures();
104 110
     void populateMapList();
105 111
     QString getExistingDirectory(QString);

+ 19
- 2
mainwindow.ui View File

@@ -228,11 +228,21 @@
228 228
                  </widget>
229 229
                 </item>
230 230
                 <item>
231
-                 <widget class="QCheckBox" name="checkBox_ToggleGrid">
231
+                 <widget class="QCheckBox" name="checkBox_smartPaths">
232 232
                   <property name="styleSheet">
233 233
                    <string notr="true">margin-left: 10px</string>
234 234
                   </property>
235 235
                   <property name="text">
236
+                   <string>Smart Paths</string>
237
+                  </property>
238
+                 </widget>
239
+                </item>
240
+                <item>
241
+                 <widget class="QCheckBox" name="checkBox_ToggleGrid">
242
+                  <property name="styleSheet">
243
+                   <string notr="true"/>
244
+                  </property>
245
+                  <property name="text">
236 246
                    <string>Show Grid</string>
237 247
                   </property>
238 248
                  </widget>
@@ -250,6 +260,13 @@
250 260
                   </property>
251 261
                  </spacer>
252 262
                 </item>
263
+                <item>
264
+                 <widget class="QPushButton" name="pushButton">
265
+                  <property name="text">
266
+                   <string>Change Dimensions</string>
267
+                  </property>
268
+                 </widget>
269
+                </item>
253 270
                </layout>
254 271
               </widget>
255 272
              </item>
@@ -291,7 +308,7 @@
291 308
                      <x>0</x>
292 309
                      <y>0</y>
293 310
                      <width>436</width>
294
-                     <height>621</height>
311
+                     <height>620</height>
295 312
                     </rect>
296 313
                    </property>
297 314
                    <layout class="QGridLayout" name="gridLayout_8">

+ 62
- 51
map.cpp View File

@@ -6,6 +6,7 @@
6 6
 #include <QImage>
7 7
 #include <QRegularExpression>
8 8
 
9
+
9 10
 Map::Map(QObject *parent) : QObject(parent)
10 11
 {
11 12
     paint_tile_index = 1;
@@ -276,6 +277,7 @@ QPixmap Map::render(bool ignoreCache = false) {
276 277
         cacheBlockdata();
277 278
         pixmap = pixmap.fromImage(image);
278 279
     }
280
+
279 281
     return pixmap;
280 282
 }
281 283
 
@@ -387,7 +389,7 @@ void Map::drawSelection(int i, int w, int selectionWidth, int selectionHeight, Q
387 389
     int y = i / w;
388 390
     painter->save();
389 391
 
390
-    QColor penColor = smart_paths_enabled ? QColor(0xff, 0x0, 0xff) : QColor(0xff, 0xff, 0xff);
392
+    QColor penColor = QColor(0xff, 0xff, 0xff);
391 393
     painter->setPen(penColor);
392 394
     int rectWidth = selectionWidth * 16;
393 395
     int rectHeight = selectionHeight * 16;
@@ -427,6 +429,36 @@ QPixmap Map::renderMetatiles() {
427 429
     return QPixmap::fromImage(image);
428 430
 }
429 431
 
432
+void Map::setNewDimensionsBlockdata(int newWidth, int newHeight) {
433
+    int oldWidth = getWidth();
434
+    int oldHeight = getHeight();
435
+
436
+    Blockdata* newBlockData = new Blockdata;
437
+
438
+    for (int y = 0; y < newHeight; y++)
439
+    for (int x = 0; x < newWidth; x++) {
440
+        if (x < oldWidth && y < oldHeight) {
441
+            int index = y * oldWidth + x;
442
+            newBlockData->addBlock(layout->blockdata->blocks->value(index));
443
+        } else {
444
+            newBlockData->addBlock(0);
445
+        }
446
+    }
447
+
448
+    layout->blockdata->copyFrom(newBlockData);
449
+}
450
+
451
+void Map::setDimensions(int newWidth, int newHeight, bool setNewBlockdata) {
452
+    if (setNewBlockdata) {
453
+        setNewDimensionsBlockdata(newWidth, newHeight);
454
+    }
455
+
456
+    layout->width = QString::number(newWidth);
457
+    layout->height = QString::number(newHeight);
458
+
459
+    emit mapChanged(this);
460
+}
461
+
430 462
 Block* Map::getBlock(int x, int y) {
431 463
     if (layout->blockdata && layout->blockdata->blocks) {
432 464
         if (x >= 0 && x < getWidth())
@@ -445,38 +477,6 @@ void Map::_setBlock(int x, int y, Block block) {
445 477
     }
446 478
 }
447 479
 
448
-void Map::_floodFill(int x, int y, uint tile) {
449
-    QList<QPoint> todo;
450
-    todo.append(QPoint(x, y));
451
-    while (todo.length()) {
452
-            QPoint point = todo.takeAt(0);
453
-            x = point.x();
454
-            y = point.y();
455
-            Block *block = getBlock(x, y);
456
-            if (block == NULL) {
457
-                continue;
458
-            }
459
-            uint old_tile = block->tile;
460
-            if (old_tile == tile) {
461
-                continue;
462
-            }
463
-            block->tile = tile;
464
-            _setBlock(x, y, *block);
465
-            if ((block = getBlock(x + 1, y)) && block->tile == old_tile) {
466
-                todo.append(QPoint(x + 1, y));
467
-            }
468
-            if ((block = getBlock(x - 1, y)) && block->tile == old_tile) {
469
-                todo.append(QPoint(x - 1, y));
470
-            }
471
-            if ((block = getBlock(x, y + 1)) && block->tile == old_tile) {
472
-                todo.append(QPoint(x, y + 1));
473
-            }
474
-            if ((block = getBlock(x, y - 1)) && block->tile == old_tile) {
475
-                todo.append(QPoint(x, y - 1));
476
-            }
477
-    }
478
-}
479
-
480 480
 void Map::_floodFillCollision(int x, int y, uint collision) {
481 481
     QList<QPoint> todo;
482 482
     todo.append(QPoint(x, y));
@@ -578,29 +578,48 @@ void Map::_floodFillCollisionElevation(int x, int y, uint collision, uint elevat
578 578
 
579 579
 
580 580
 void Map::undo() {
581
+    HistoryItem *commit = history.back();
582
+    if (!commit)
583
+        return;
584
+
581 585
     if (layout->blockdata) {
582
-        Blockdata *commit = history.back();
583
-        if (commit != NULL) {
584
-            layout->blockdata->copyFrom(commit);
585
-            emit mapChanged(this);
586
+        layout->blockdata->copyFrom(commit->metatiles);
587
+        if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight())
588
+        {
589
+            this->setDimensions(commit->layoutWidth, commit->layoutHeight, false);
590
+            emit mapNeedsRedrawing(this);
586 591
         }
592
+
593
+        emit mapChanged(this);
587 594
     }
588 595
 }
589 596
 
590 597
 void Map::redo() {
598
+    HistoryItem *commit = history.next();
599
+    if (!commit)
600
+        return;
601
+
591 602
     if (layout->blockdata) {
592
-        Blockdata *commit = history.next();
593
-        if (commit != NULL) {
594
-            layout->blockdata->copyFrom(commit);
595
-            emit mapChanged(this);
603
+        layout->blockdata->copyFrom(commit->metatiles);
604
+        if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight())
605
+        {
606
+            this->setDimensions(commit->layoutWidth, commit->layoutHeight, false);
607
+            emit mapNeedsRedrawing(this);
596 608
         }
609
+
610
+        emit mapChanged(this);
597 611
     }
598 612
 }
599 613
 
600 614
 void Map::commit() {
601 615
     if (layout->blockdata) {
602
-        if (!layout->blockdata->equals(history.current())) {
603
-            Blockdata* commit = layout->blockdata->copy();
616
+        HistoryItem *item = history.current();
617
+        bool atCurrentHistory = item
618
+                && layout->blockdata->equals(item->metatiles)
619
+                && this->getWidth() == item->layoutWidth
620
+                && this->getHeight() == item->layoutHeight;
621
+        if (!atCurrentHistory) {
622
+            HistoryItem *commit = new HistoryItem(layout->blockdata->copy(), this->getWidth(), this->getHeight());
604 623
             history.push(commit);
605 624
             emit mapChanged(this);
606 625
         }
@@ -615,14 +634,6 @@ void Map::setBlock(int x, int y, Block block) {
615 634
     }
616 635
 }
617 636
 
618
-void Map::floodFill(int x, int y, uint tile) {
619
-    Block *block = getBlock(x, y);
620
-    if (block && block->tile != tile) {
621
-        _floodFill(x, y, tile);
622
-        commit();
623
-    }
624
-}
625
-
626 637
 void Map::floodFillCollision(int x, int y, uint collision) {
627 638
     Block *block = getBlock(x, y);
628 639
     if (block && block->collision != collision) {

+ 15
- 3
map.h View File

@@ -10,6 +10,17 @@
10 10
 #include <QDebug>
11 11
 #include <QGraphicsPixmapItem>
12 12
 
13
+class HistoryItem {
14
+public:
15
+    Blockdata *metatiles;
16
+    short layoutWidth;
17
+    short layoutHeight;
18
+    HistoryItem(Blockdata *metatiles_, short layoutWidth_, short layoutHeight_) {
19
+        this->metatiles = metatiles_;
20
+        this->layoutWidth = layoutWidth_;
21
+        this->layoutHeight = layoutHeight_;
22
+    }
23
+};
13 24
 
14 25
 template <typename T>
15 26
 class History {
@@ -173,8 +184,6 @@ public:
173 184
     void setBlock(int x, int y, Block block);
174 185
     void _setBlock(int x, int y, Block block);
175 186
 
176
-    void floodFill(int x, int y, uint tile);
177
-    void _floodFill(int x, int y, uint tile);
178 187
     void floodFillCollision(int x, int y, uint collision);
179 188
     void _floodFillCollision(int x, int y, uint collision);
180 189
     void floodFillElevation(int x, int y, uint elevation);
@@ -182,7 +191,7 @@ public:
182 191
     void floodFillCollisionElevation(int x, int y, uint collision, uint elevation);
183 192
     void _floodFillCollisionElevation(int x, int y, uint collision, uint elevation);
184 193
 
185
-    History<Blockdata*> history;
194
+    History<HistoryItem*> history;
186 195
     void undo();
187 196
     void redo();
188 197
     void commit();
@@ -194,6 +203,8 @@ public:
194 203
 
195 204
     QList<Connection*> connections;
196 205
     QPixmap renderConnection(Connection);
206
+    void setNewDimensionsBlockdata(int newWidth, int newHeight);
207
+    void setDimensions(int newWidth, int newHeight, bool setNewBlockData = true);
197 208
 
198 209
     QPixmap renderBorder();
199 210
     void cacheBorder();
@@ -212,6 +223,7 @@ signals:
212 223
     void paintTileChanged(Map *map);
213 224
     void paintCollisionChanged(Map *map);
214 225
     void mapChanged(Map *map);
226
+    void mapNeedsRedrawing(Map *map);
215 227
     void statusBarMessage(QString);
216 228
 
217 229
 public slots: