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
 
26
 
27
 void Editor::undo() {
27
 void Editor::undo() {
28
     if (current_view) {
28
     if (current_view) {
29
-        ((MapPixmapItem*)current_view)->undo();
29
+        map->undo();
30
+        map_item->draw();
30
     }
31
     }
31
 }
32
 }
32
 
33
 
33
 void Editor::redo() {
34
 void Editor::redo() {
34
     if (current_view) {
35
     if (current_view) {
35
-        ((MapPixmapItem*)current_view)->redo();
36
+        map->redo();
37
+        map_item->draw();
36
     }
38
     }
37
 }
39
 }
38
 
40
 
58
 void Editor::setEditingCollision() {
60
 void Editor::setEditingCollision() {
59
     current_view = collision_item;
61
     current_view = collision_item;
60
     if (collision_item) {
62
     if (collision_item) {
63
+        displayMapConnections();
61
         collision_item->draw();
64
         collision_item->draw();
62
         collision_item->setVisible(true);
65
         collision_item->setVisible(true);
63
         setConnectionsVisibility(true);
66
         setConnectionsVisibility(true);
318
     }
321
     }
319
     if (project) {
322
     if (project) {
320
         map = project->loadMap(map_name);
323
         map = project->loadMap(map_name);
321
-        displayMap();
322
         selected_events->clear();
324
         selected_events->clear();
325
+        displayMap();
323
         updateSelectedEvents();
326
         updateSelectedEvents();
324
     }
327
     }
325
 }
328
 }
879
         map->paint_tile_index = baseTileY * 8 + baseTileX;
882
         map->paint_tile_index = baseTileY * 8 + baseTileX;
880
         map->paint_tile_width = abs(map->paint_metatile_initial_x - x) + 1;
883
         map->paint_tile_width = abs(map->paint_metatile_initial_x - x) + 1;
881
         map->paint_tile_height = abs(map->paint_metatile_initial_y - y) + 1;
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
         emit map->paintTileChanged(map);
885
         emit map->paintTileChanged(map);
886
     }
886
     }
887
 }
887
 }
1029
         int x = (int)(pos.x()) / 16;
1029
         int x = (int)(pos.x()) / 16;
1030
         int y = (int)(pos.y()) / 16;
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
             paintSmartPath(x, y);
1033
             paintSmartPath(x, y);
1034
         } else {
1034
         } else {
1035
             paintNormal(x, y);
1035
             paintNormal(x, y);
1157
         QPointF pos = event->pos();
1157
         QPointF pos = event->pos();
1158
         int x = (int)(pos.x()) / 16;
1158
         int x = (int)(pos.x()) / 16;
1159
         int y = (int)(pos.y()) / 16;
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
         draw();
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
 void MapPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
1317
 void MapPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
1166
     QPointF pos = event->pos();
1318
     QPointF pos = event->pos();
1167
     int x = (int)(pos.x()) / 16;
1319
     int x = (int)(pos.x()) / 16;
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
 void MapPixmapItem::updateCurHoveredTile(QPointF pos) {
1370
 void MapPixmapItem::updateCurHoveredTile(QPointF pos) {
1233
     int x = ((int)pos.x()) / 16;
1371
     int x = ((int)pos.x()) / 16;
1234
     int y = ((int)pos.y()) / 16;
1372
     int y = ((int)pos.y()) / 16;

+ 2
- 2
editor.h View File

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

+ 86
- 10
mainwindow.cpp View File

15
 #include <QSpacerItem>
15
 #include <QSpacerItem>
16
 #include <QFont>
16
 #include <QFont>
17
 #include <QScrollBar>
17
 #include <QScrollBar>
18
+#include <QMessageBox>
19
+#include <QDialogButtonBox>
18
 
20
 
19
 MainWindow::MainWindow(QWidget *parent) :
21
 MainWindow::MainWindow(QWidget *parent) :
20
     QMainWindow(parent),
22
     QMainWindow(parent),
147
         return;
149
         return;
148
     }
150
     }
149
     editor->setMap(map_name);
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
     on_tabWidget_currentChanged(ui->tabWidget->currentIndex());
168
     on_tabWidget_currentChanged(ui->tabWidget->currentIndex());
152
 
169
 
153
     ui->graphicsView_Map->setScene(editor->scene);
170
     ui->graphicsView_Map->setScene(editor->scene);
177
     ui->graphicsView_Elevation->setScene(editor->scene_elevation_metatiles);
194
     ui->graphicsView_Elevation->setScene(editor->scene_elevation_metatiles);
178
     //ui->graphicsView_Elevation->setSceneRect(editor->scene_elevation_metatiles->sceneRect());
195
     //ui->graphicsView_Elevation->setSceneRect(editor->scene_elevation_metatiles->sceneRect());
179
     ui->graphicsView_Elevation->setFixedSize(editor->elevation_metatiles_item->pixmap().width() + 2, editor->elevation_metatiles_item->pixmap().height() + 2);
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
 void MainWindow::setRecentMap(QString map_name) {
199
 void MainWindow::setRecentMap(QString map_name) {
785
     updateMapList();
792
     updateMapList();
786
 }
793
 }
787
 
794
 
795
+void MainWindow::onMapNeedsRedrawing(Map *map) {
796
+    redrawMapScene();
797
+}
798
+
788
 void MainWindow::on_action_Export_Map_Image_triggered()
799
 void MainWindow::on_action_Export_Map_Image_triggered()
789
 {
800
 {
790
     QString defaultFilepath = QString("%1/%2.png").arg(editor->project->root).arg(editor->map->name);
801
     QString defaultFilepath = QString("%1/%2.png").arg(editor->project->root).arg(editor->map->name);
838
 {
849
 {
839
     editor->updateSecondaryTileset(tilesetLabel);
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
 
38
 
39
     void onLoadMapRequested(QString, QString);
39
     void onLoadMapRequested(QString, QString);
40
     void onMapChanged(Map *map);
40
     void onMapChanged(Map *map);
41
+    void onMapNeedsRedrawing(Map *map);
41
 
42
 
42
     void on_action_Save_triggered();
43
     void on_action_Save_triggered();
43
     void on_tabWidget_2_currentChanged(int index);
44
     void on_tabWidget_2_currentChanged(int index);
93
 
94
 
94
     void on_comboBox_SecondaryTileset_activated(const QString &arg1);
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
 private:
101
 private:
97
     Ui::MainWindow *ui;
102
     Ui::MainWindow *ui;
98
     QStandardItemModel *mapListModel;
103
     QStandardItemModel *mapListModel;
100
     Editor *editor = NULL;
105
     Editor *editor = NULL;
101
     QIcon* mapIcon;
106
     QIcon* mapIcon;
102
     void setMap(QString);
107
     void setMap(QString);
108
+    void redrawMapScene();
103
     void loadDataStructures();
109
     void loadDataStructures();
104
     void populateMapList();
110
     void populateMapList();
105
     QString getExistingDirectory(QString);
111
     QString getExistingDirectory(QString);

+ 19
- 2
mainwindow.ui View File

228
                  </widget>
228
                  </widget>
229
                 </item>
229
                 </item>
230
                 <item>
230
                 <item>
231
-                 <widget class="QCheckBox" name="checkBox_ToggleGrid">
231
+                 <widget class="QCheckBox" name="checkBox_smartPaths">
232
                   <property name="styleSheet">
232
                   <property name="styleSheet">
233
                    <string notr="true">margin-left: 10px</string>
233
                    <string notr="true">margin-left: 10px</string>
234
                   </property>
234
                   </property>
235
                   <property name="text">
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
                    <string>Show Grid</string>
246
                    <string>Show Grid</string>
237
                   </property>
247
                   </property>
238
                  </widget>
248
                  </widget>
250
                   </property>
260
                   </property>
251
                  </spacer>
261
                  </spacer>
252
                 </item>
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
                </layout>
270
                </layout>
254
               </widget>
271
               </widget>
255
              </item>
272
              </item>
291
                      <x>0</x>
308
                      <x>0</x>
292
                      <y>0</y>
309
                      <y>0</y>
293
                      <width>436</width>
310
                      <width>436</width>
294
-                     <height>621</height>
311
+                     <height>620</height>
295
                     </rect>
312
                     </rect>
296
                    </property>
313
                    </property>
297
                    <layout class="QGridLayout" name="gridLayout_8">
314
                    <layout class="QGridLayout" name="gridLayout_8">

+ 62
- 51
map.cpp View File

6
 #include <QImage>
6
 #include <QImage>
7
 #include <QRegularExpression>
7
 #include <QRegularExpression>
8
 
8
 
9
+
9
 Map::Map(QObject *parent) : QObject(parent)
10
 Map::Map(QObject *parent) : QObject(parent)
10
 {
11
 {
11
     paint_tile_index = 1;
12
     paint_tile_index = 1;
276
         cacheBlockdata();
277
         cacheBlockdata();
277
         pixmap = pixmap.fromImage(image);
278
         pixmap = pixmap.fromImage(image);
278
     }
279
     }
280
+
279
     return pixmap;
281
     return pixmap;
280
 }
282
 }
281
 
283
 
387
     int y = i / w;
389
     int y = i / w;
388
     painter->save();
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
     painter->setPen(penColor);
393
     painter->setPen(penColor);
392
     int rectWidth = selectionWidth * 16;
394
     int rectWidth = selectionWidth * 16;
393
     int rectHeight = selectionHeight * 16;
395
     int rectHeight = selectionHeight * 16;
427
     return QPixmap::fromImage(image);
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
 Block* Map::getBlock(int x, int y) {
462
 Block* Map::getBlock(int x, int y) {
431
     if (layout->blockdata && layout->blockdata->blocks) {
463
     if (layout->blockdata && layout->blockdata->blocks) {
432
         if (x >= 0 && x < getWidth())
464
         if (x >= 0 && x < getWidth())
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
 void Map::_floodFillCollision(int x, int y, uint collision) {
480
 void Map::_floodFillCollision(int x, int y, uint collision) {
481
     QList<QPoint> todo;
481
     QList<QPoint> todo;
482
     todo.append(QPoint(x, y));
482
     todo.append(QPoint(x, y));
578
 
578
 
579
 
579
 
580
 void Map::undo() {
580
 void Map::undo() {
581
+    HistoryItem *commit = history.back();
582
+    if (!commit)
583
+        return;
584
+
581
     if (layout->blockdata) {
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
 void Map::redo() {
597
 void Map::redo() {
598
+    HistoryItem *commit = history.next();
599
+    if (!commit)
600
+        return;
601
+
591
     if (layout->blockdata) {
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
 void Map::commit() {
614
 void Map::commit() {
601
     if (layout->blockdata) {
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
             history.push(commit);
623
             history.push(commit);
605
             emit mapChanged(this);
624
             emit mapChanged(this);
606
         }
625
         }
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
 void Map::floodFillCollision(int x, int y, uint collision) {
637
 void Map::floodFillCollision(int x, int y, uint collision) {
627
     Block *block = getBlock(x, y);
638
     Block *block = getBlock(x, y);
628
     if (block && block->collision != collision) {
639
     if (block && block->collision != collision) {

+ 15
- 3
map.h View File

10
 #include <QDebug>
10
 #include <QDebug>
11
 #include <QGraphicsPixmapItem>
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
 template <typename T>
25
 template <typename T>
15
 class History {
26
 class History {
173
     void setBlock(int x, int y, Block block);
184
     void setBlock(int x, int y, Block block);
174
     void _setBlock(int x, int y, Block block);
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
     void floodFillCollision(int x, int y, uint collision);
187
     void floodFillCollision(int x, int y, uint collision);
179
     void _floodFillCollision(int x, int y, uint collision);
188
     void _floodFillCollision(int x, int y, uint collision);
180
     void floodFillElevation(int x, int y, uint elevation);
189
     void floodFillElevation(int x, int y, uint elevation);
182
     void floodFillCollisionElevation(int x, int y, uint collision, uint elevation);
191
     void floodFillCollisionElevation(int x, int y, uint collision, uint elevation);
183
     void _floodFillCollisionElevation(int x, int y, uint collision, uint elevation);
192
     void _floodFillCollisionElevation(int x, int y, uint collision, uint elevation);
184
 
193
 
185
-    History<Blockdata*> history;
194
+    History<HistoryItem*> history;
186
     void undo();
195
     void undo();
187
     void redo();
196
     void redo();
188
     void commit();
197
     void commit();
194
 
203
 
195
     QList<Connection*> connections;
204
     QList<Connection*> connections;
196
     QPixmap renderConnection(Connection);
205
     QPixmap renderConnection(Connection);
206
+    void setNewDimensionsBlockdata(int newWidth, int newHeight);
207
+    void setDimensions(int newWidth, int newHeight, bool setNewBlockData = true);
197
 
208
 
198
     QPixmap renderBorder();
209
     QPixmap renderBorder();
199
     void cacheBorder();
210
     void cacheBorder();
212
     void paintTileChanged(Map *map);
223
     void paintTileChanged(Map *map);
213
     void paintCollisionChanged(Map *map);
224
     void paintCollisionChanged(Map *map);
214
     void mapChanged(Map *map);
225
     void mapChanged(Map *map);
226
+    void mapNeedsRedrawing(Map *map);
215
     void statusBarMessage(QString);
227
     void statusBarMessage(QString);
216
 
228
 
217
 public slots:
229
 public slots: