diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index 7ed791e1..f7e9e245 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -1270,7 +1270,7 @@ - + 0 diff --git a/forms/prefabcreationdialog.ui b/forms/prefabcreationdialog.ui new file mode 100644 index 00000000..aa9041f7 --- /dev/null +++ b/forms/prefabcreationdialog.ui @@ -0,0 +1,201 @@ + + + PrefabCreationDialog + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + false + + + + + + <html><head/><body><p><span style=" font-weight:600;">Tip</span>: Click on individual metatiles to remove them from the Prefab</p></body></html> + + + Qt::RichText + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + true + + + + + 0 + 0 + 363 + 192 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + background-color: transparent + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Prefab Name + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + ClickableGraphicsView + QGraphicsView +
graphicsview.h
+
+
+ + + + buttonBox + accepted() + PrefabCreationDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PrefabCreationDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/include/mainwindow.h b/include/mainwindow.h index 703d6b95..599d6e1e 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -354,6 +354,7 @@ private slots: void on_pushButton_NewWildMonGroup_clicked(); void on_pushButton_DeleteWildMonGroup_clicked(); void on_pushButton_ConfigureEncountersJSON_clicked(); + void on_pushButton_CreatePrefab_clicked(); void on_actionRegion_Map_Editor_triggered(); void on_actionEdit_Preferences_triggered(); diff --git a/include/ui/graphicsview.h b/include/ui/graphicsview.h index b7ea81bf..e9b87326 100644 --- a/include/ui/graphicsview.h +++ b/include/ui/graphicsview.h @@ -14,11 +14,15 @@ public: public: void mousePressEvent(QMouseEvent *event) { QGraphicsView::mousePressEvent(event); - emit this->clicked(); + emit this->clicked(event); + } + void mouseDoubleClickEvent(QMouseEvent *event) { + QGraphicsView::mouseDoubleClickEvent(event); + emit this->clicked(event); } signals: - void clicked(); + void clicked(QMouseEvent *event); }; class Editor; diff --git a/include/ui/prefab.h b/include/ui/prefab.h index b529615b..fac2d8d5 100644 --- a/include/ui/prefab.h +++ b/include/ui/prefab.h @@ -18,11 +18,16 @@ struct PrefabItem class Prefab { public: - void initPrefabUI(MetatileSelector *selector, QWidget *prefabWidget, QLabel *emptyPrefabLabel, QString primaryTileset, QString secondaryTileset, Map *map); + void initPrefabUI(MetatileSelector *selector, QWidget *prefabWidget, QLabel *emptyPrefabLabel, Map *map); + void addPrefab(MetatileSelection selection, Map *map, QString name); private: + MetatileSelector *selector; + QWidget *prefabWidget; + QLabel *emptyPrefabLabel; QList items; void loadPrefabs(); + void updatePrefabUi(Map *map); QList getPrefabsForTilesets(QString primaryTileset, QString secondaryTileset); }; diff --git a/include/ui/prefabcreationdialog.h b/include/ui/prefabcreationdialog.h new file mode 100644 index 00000000..5748f35a --- /dev/null +++ b/include/ui/prefabcreationdialog.h @@ -0,0 +1,28 @@ +#ifndef PREFABCREATIONDIALOG_H +#define PREFABCREATIONDIALOG_H + +#include "metatileselector.h" +#include "map.h" + +#include + +namespace Ui { +class PrefabCreationDialog; +} + +class PrefabCreationDialog : public QDialog +{ + Q_OBJECT + +public: + explicit PrefabCreationDialog(QWidget *parent, MetatileSelector *metatileSelector, Map *map); + ~PrefabCreationDialog(); + void savePrefab(); + +private: + Map *map; + Ui::PrefabCreationDialog *ui; + MetatileSelection selection; +}; + +#endif // PREFABCREATIONDIALOG_H diff --git a/porymap.pro b/porymap.pro index d37b915d..3341f4b6 100644 --- a/porymap.pro +++ b/porymap.pro @@ -55,6 +55,7 @@ SOURCES += src/core/block.cpp \ src/ui/graphicsview.cpp \ src/ui/imageproviders.cpp \ src/ui/mappixmapitem.cpp \ + src/ui/prefabcreationdialog.cpp \ src/ui/regionmappixmapitem.cpp \ src/ui/citymappixmapitem.cpp \ src/ui/mapsceneeventfilter.cpp \ @@ -138,6 +139,7 @@ HEADERS += include/core/block.h \ include/ui/graphicsview.h \ include/ui/imageproviders.h \ include/ui/mappixmapitem.h \ + include/ui/prefabcreationdialog.h \ include/ui/regionmappixmapitem.h \ include/ui/citymappixmapitem.h \ include/ui/mapsceneeventfilter.h \ @@ -180,6 +182,7 @@ HEADERS += include/core/block.h \ FORMS += forms/mainwindow.ui \ forms/eventpropertiesframe.ui \ + forms/prefabcreationdialog.ui \ forms/prefabframe.ui \ forms/tileseteditor.ui \ forms/paletteeditor.ui \ diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 00467203..9e16f763 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -6,6 +6,7 @@ #include "editor.h" #include "eventpropertiesframe.h" #include "ui_eventpropertiesframe.h" +#include "prefabcreationdialog.h" #include "bordermetatilespixmapitem.h" #include "currentselectedmetatilespixmapitem.h" #include "customattributestable.h" @@ -557,8 +558,6 @@ bool MainWindow::openProject(QString dir) { editor->metatile_selector_item, ui->scrollAreaWidgetContents_Prefabs, ui->label_prefabHelp, - editor->ui->comboBox_PrimaryTileset->currentText(), - editor->ui->comboBox_SecondaryTileset->currentText(), editor->map); for (auto action : this->registeredActions) { this->ui->menuTools->removeAction(action); @@ -3176,6 +3175,15 @@ void MainWindow::on_actionRegion_Map_Editor_triggered() { } } +void MainWindow::on_pushButton_CreatePrefab_clicked() { + PrefabCreationDialog dialog(this, this->editor->metatile_selector_item, this->editor->map); + dialog.setWindowTitle("Create Prefab"); + dialog.setWindowModality(Qt::NonModal); + if (dialog.exec() == QDialog::Accepted) { + dialog.savePrefab(); + } +} + bool MainWindow::initRegionMapEditor() { this->regionMapEditor = new RegionMapEditor(this, this->editor->project); this->regionMapEditor->setAttribute(Qt::WA_DeleteOnClose); diff --git a/src/ui/mappixmapitem.cpp b/src/ui/mappixmapitem.cpp index c245f4cb..f44922a4 100644 --- a/src/ui/mappixmapitem.cpp +++ b/src/ui/mappixmapitem.cpp @@ -177,11 +177,22 @@ bool isSmartPathTile(QList metatileItems, uint16_t metati return false; } +bool isValidSmartPathSelection(MetatileSelection selection) { + if (selection.dimensions.x() != 3 || selection.dimensions.y() != 3) + return false; + + for (int i = 0; i < selection.metatileItems.length(); i++) { + if (!selection.metatileItems.at(i).enabled) + return false; + } + + return true; +} + void MapPixmapItem::paintSmartPath(int x, int y, bool fromScriptCall) { MetatileSelection selection = this->metatileSelector->getMetatileSelection(); - - // Smart path should never be enabled without a 3x3 block selection. - if (selection.dimensions.x() != 3 || selection.dimensions.y() != 3) return; + if (!isValidSmartPathSelection(selection)) + return; // Shift to the middle tile of the smart path selection. uint16_t openTile = selection.metatileItems.at(4).metatileId; @@ -420,13 +431,15 @@ void MapPixmapItem::magicFill( if (i < 0) i = selectionDimensions.x() + i; if (j < 0) j = selectionDimensions.y() + j; int index = j * selectionDimensions.x() + i; - block.metatileId = selectedMetatiles.at(index).metatileId; - if (setCollisions) { - CollisionSelectionItem item = selectedCollisions.at(index); - block.collision = item.collision; - block.elevation = item.elevation; + if (selectedMetatiles.at(index).enabled) { + block.metatileId = selectedMetatiles.at(index).metatileId; + if (setCollisions) { + CollisionSelectionItem item = selectedCollisions.at(index); + block.collision = item.collision; + block.elevation = item.elevation; + } + map->setBlock(x, y, block, !fromScriptCall); } - map->setBlock(x, y, block, !fromScriptCall); } } } @@ -480,7 +493,7 @@ void MapPixmapItem::floodFill( int index = j * selectionDimensions.x() + i; uint16_t metatileId = selectedMetatiles.at(index).metatileId; uint16_t old_metatileId = block.metatileId; - if (selectedMetatiles.count() != 1 || old_metatileId != metatileId) { + if (selectedMetatiles.at(index).enabled && (selectedMetatiles.count() != 1 || old_metatileId != metatileId)) { block.metatileId = metatileId; if (setCollisions) { CollisionSelectionItem item = selectedCollisions.at(index); @@ -514,9 +527,8 @@ void MapPixmapItem::floodFill( void MapPixmapItem::floodFillSmartPath(int initialX, int initialY, bool fromScriptCall) { MetatileSelection selection = this->metatileSelector->getMetatileSelection(); - - // Smart path should never be enabled without a 3x3 block selection. - if (selection.dimensions.x() != 3 || selection.dimensions.y() != 3) return; + if (!isValidSmartPathSelection(selection)) + return; // Shift to the middle tile of the smart path selection. uint16_t openTile = selection.metatileItems.at(4).metatileId; diff --git a/src/ui/prefab.cpp b/src/ui/prefab.cpp index da6d11dd..31850ddf 100644 --- a/src/ui/prefab.cpp +++ b/src/ui/prefab.cpp @@ -4,6 +4,7 @@ #include "ui_prefabframe.h" #include "parseutil.h" #include "currentselectedmetatilespixmapitem.h" +#include "log.h" #include #include @@ -86,9 +87,29 @@ QList Prefab::getPrefabsForTilesets(QString primaryTileset, QString return filteredPrefabs; } -void Prefab::initPrefabUI(MetatileSelector *selector, QWidget *prefabWidget, QLabel *emptyPrefabLabel, QString primaryTileset, QString secondaryTileset, Map *map) { +void Prefab::initPrefabUI(MetatileSelector *selector, QWidget *prefabWidget, QLabel *emptyPrefabLabel, Map *map) { + logInfo("initPrefabUI"); + this->selector = selector; + this->prefabWidget = prefabWidget; + this->emptyPrefabLabel = emptyPrefabLabel; this->loadPrefabs(); - QList prefabs = this->getPrefabsForTilesets(primaryTileset, secondaryTileset); + logInfo("initPrefabUI loaded prefabs"); + this->updatePrefabUi(map); + logInfo("initPrefabUI after updatePrefabUi"); +} + +void Prefab::updatePrefabUi(Map *map) { + // Cleanup the PrefabFrame to have a clean slate. + auto layout = this->prefabWidget->layout(); + while (layout && layout->count() > 1) { + auto child = layout->takeAt(1); + if (child->widget()) { + delete child->widget(); + } + delete child; + } + + QList prefabs = this->getPrefabsForTilesets(map->layout->tileset_primary_label, map->layout->tileset_secondary_label); if (prefabs.isEmpty()) { emptyPrefabLabel->setVisible(true); return; @@ -115,5 +136,10 @@ void Prefab::initPrefabUI(MetatileSelector *selector, QWidget *prefabWidget, QLa prefabWidget->layout()->addItem(spacer); } +void Prefab::addPrefab(MetatileSelection selection, Map *map, QString name) { + this->items.append(PrefabItem{name, map->layout->tileset_primary_label, map->layout->tileset_secondary_label, selection}); + this->updatePrefabUi(map); +} + Prefab prefab; diff --git a/src/ui/prefabcreationdialog.cpp b/src/ui/prefabcreationdialog.cpp new file mode 100644 index 00000000..976a53a1 --- /dev/null +++ b/src/ui/prefabcreationdialog.cpp @@ -0,0 +1,49 @@ +#include "prefabcreationdialog.h" +#include "ui_prefabcreationdialog.h" +#include "currentselectedmetatilespixmapitem.h" +#include "graphicsview.h" +#include "prefab.h" + +#include + +PrefabCreationDialog::PrefabCreationDialog(QWidget *parent, MetatileSelector *metatileSelector, Map *map) : + QDialog(parent), + ui(new Ui::PrefabCreationDialog) +{ + ui->setupUi(this); + + this->map = map; + this->selection = metatileSelector->getMetatileSelection(); + QGraphicsScene *scene = new QGraphicsScene; + QGraphicsPixmapItem *pixmapItem = scene->addPixmap(drawMetatileSelection(this->selection, map)); + scene->setSceneRect(scene->itemsBoundingRect()); + this->ui->graphicsView_Prefab->setScene(scene); + this->ui->graphicsView_Prefab->setFixedSize(scene->itemsBoundingRect().width() + 2, + scene->itemsBoundingRect().height() + 2); + + QObject::connect(this->ui->graphicsView_Prefab, &ClickableGraphicsView::clicked, [=](QMouseEvent *event){ + auto pos = event->pos(); + int selectionWidth = this->selection.dimensions.x() * 16; + int selectionHeight = this->selection.dimensions.y() * 16; + if (pos.x() < 0 || pos.x() >= selectionWidth || pos.y() < 0 || pos.y() >= selectionHeight) + return; + int metatileX = pos.x() / 16; + int metatileY = pos.y() / 16; + int index = metatileY * this->selection.dimensions.x() + metatileX; + bool toggledState = !this->selection.metatileItems[index].enabled; + this->selection.metatileItems[index].enabled = toggledState; + if (this->selection.hasCollision) { + this->selection.collisionItems[index].enabled = toggledState; + } + pixmapItem->setPixmap(drawMetatileSelection(this->selection, map)); + }); +} + +PrefabCreationDialog::~PrefabCreationDialog() +{ + delete ui; +} + +void PrefabCreationDialog::savePrefab() { + prefab.addPrefab(this->selection, this->map, this->ui->lineEdit_PrefabName->text()); +}