1401 lines
54 KiB
C++
1401 lines
54 KiB
C++
#include "regionmapeditor.h"
|
|
#include "ui_regionmapeditor.h"
|
|
#include "regionmappropertiesdialog.h"
|
|
#include "regionmapeditcommands.h"
|
|
#include "imageexport.h"
|
|
#include "shortcut.h"
|
|
#include "config.h"
|
|
#include "log.h"
|
|
|
|
#include <QDir>
|
|
#include <QDialog>
|
|
#include <QDialogButtonBox>
|
|
#include <QFileDialog>
|
|
#include <QFormLayout>
|
|
#include <QLineEdit>
|
|
#include <QSpinBox>
|
|
#include <QColor>
|
|
#include <QMessageBox>
|
|
#include <QTransform>
|
|
#include <math.h>
|
|
|
|
using OrderedJson = poryjson::Json;
|
|
using OrderedJsonDoc = poryjson::JsonDoc;
|
|
|
|
RegionMapEditor::RegionMapEditor(QWidget *parent, Project *project) :
|
|
QMainWindow(parent),
|
|
ui(new Ui::RegionMapEditor)
|
|
{
|
|
this->ui->setupUi(this);
|
|
this->project = project;
|
|
this->initShortcuts();
|
|
this->restoreWindowState();
|
|
}
|
|
|
|
RegionMapEditor::~RegionMapEditor()
|
|
{
|
|
this->region_map = nullptr;
|
|
// deletion must be done in this order else crashes
|
|
auto stacks = this->history.stacks();
|
|
for (auto *stack : stacks) {
|
|
this->history.removeStack(stack);
|
|
}
|
|
for (auto p : this->region_maps) {
|
|
delete p.second;
|
|
}
|
|
delete region_map_item;
|
|
delete mapsquare_selector_item;
|
|
delete region_map_layout_item;
|
|
delete scene_region_map_image;
|
|
delete scene_region_map_layout;
|
|
delete scene_region_map_tiles;
|
|
delete ui;
|
|
}
|
|
|
|
void RegionMapEditor::restoreWindowState() {
|
|
logInfo("Restoring region map editor geometry from previous session.");
|
|
QMap<QString, QByteArray> geometry = porymapConfig.getRegionMapEditorGeometry();
|
|
this->restoreGeometry(geometry.value("region_map_editor_geometry"));
|
|
this->restoreState(geometry.value("region_map_editor_state"));
|
|
}
|
|
|
|
void RegionMapEditor::initShortcuts() {
|
|
auto *shortcut_RM_Options_delete = new Shortcut(
|
|
{QKeySequence("Del"), QKeySequence("Backspace")}, this, SLOT(on_pushButton_RM_Options_delete_clicked()));
|
|
shortcut_RM_Options_delete->setObjectName("shortcut_RM_Options_delete");
|
|
shortcut_RM_Options_delete->setWhatsThis("Map Layout: Delete Square");
|
|
|
|
QAction *undoAction = this->history.createUndoAction(this, tr("&Undo"));
|
|
undoAction->setObjectName("action_RegionMap_Undo");
|
|
undoAction->setShortcut(QKeySequence("Ctrl+Z"));
|
|
|
|
QAction *redoAction = this->history.createRedoAction(this, tr("&Redo"));
|
|
redoAction->setObjectName("action_RegionMap_Redo");
|
|
redoAction->setShortcuts({QKeySequence("Ctrl+Y"), QKeySequence("Ctrl+Shift+Z")});
|
|
|
|
ui->menuEdit->addAction(undoAction);
|
|
ui->menuEdit->addAction(redoAction);
|
|
|
|
shortcutsConfig.load();
|
|
shortcutsConfig.setDefaultShortcuts(shortcutableObjects());
|
|
applyUserShortcuts();
|
|
|
|
connect(&(this->history), &QUndoGroup::indexChanged, [this](int) {
|
|
on_tabWidget_Region_Map_currentChanged(this->ui->tabWidget_Region_Map->currentIndex());
|
|
});
|
|
}
|
|
|
|
QObjectList RegionMapEditor::shortcutableObjects() const {
|
|
QObjectList shortcutable_objects;
|
|
|
|
for (auto *action : findChildren<QAction *>())
|
|
if (!action->objectName().isEmpty())
|
|
shortcutable_objects.append(qobject_cast<QObject *>(action));
|
|
for (auto *shortcut : findChildren<Shortcut *>())
|
|
if (!shortcut->objectName().isEmpty())
|
|
shortcutable_objects.append(qobject_cast<QObject *>(shortcut));
|
|
|
|
return shortcutable_objects;
|
|
}
|
|
|
|
void RegionMapEditor::applyUserShortcuts() {
|
|
for (auto *action : findChildren<QAction *>())
|
|
if (!action->objectName().isEmpty())
|
|
action->setShortcuts(shortcutsConfig.userShortcuts(action));
|
|
for (auto *shortcut : findChildren<Shortcut *>())
|
|
if (!shortcut->objectName().isEmpty())
|
|
shortcut->setKeys(shortcutsConfig.userShortcuts(shortcut));
|
|
}
|
|
|
|
bool RegionMapEditor::loadRegionMapEntries() {
|
|
this->region_map_entries.clear();
|
|
|
|
QString regionMapSectionFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
|
|
|
|
ParseUtil parser;
|
|
QJsonDocument sectionsDoc;
|
|
if (!parser.tryParseJsonFile(§ionsDoc, regionMapSectionFilepath)) {
|
|
logError(QString("Failed to read map data from %1").arg(regionMapSectionFilepath));
|
|
return false;
|
|
}
|
|
|
|
// for some unknown reason, the OrderedJson class would not parse this properly
|
|
// perhaps updating nlohmann/json here would fix it, but that also requires using C++17
|
|
QJsonObject object = sectionsDoc.object();
|
|
|
|
for (auto entryRef : object["map_sections"].toArray()) {
|
|
QJsonObject entryObject = entryRef.toObject();
|
|
QString entryMapSection = ParseUtil::jsonToQString(entryObject["map_section"]);
|
|
MapSectionEntry entry;
|
|
entry.name = ParseUtil::jsonToQString(entryObject["name"]);
|
|
entry.x = ParseUtil::jsonToInt(entryObject["x"]);
|
|
entry.y = ParseUtil::jsonToInt(entryObject["y"]);
|
|
entry.width = ParseUtil::jsonToInt(entryObject["width"]);
|
|
entry.height = ParseUtil::jsonToInt(entryObject["height"]);
|
|
entry.valid = true;
|
|
this->region_map_entries[entryMapSection] = entry;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RegionMapEditor::saveRegionMapEntries() {
|
|
QString regionMapSectionFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
|
|
|
|
QFile sectionsFile(regionMapSectionFilepath);
|
|
if (!sectionsFile.open(QIODevice::WriteOnly)) {
|
|
logError(QString("Error: Could not open %1 for writing").arg(regionMapSectionFilepath));
|
|
return false;
|
|
}
|
|
|
|
OrderedJson::object object;
|
|
OrderedJson::array mapSectionArray;
|
|
|
|
for (auto pair : this->region_map_entries) {
|
|
QString section = pair.first;
|
|
MapSectionEntry entry = pair.second;
|
|
|
|
OrderedJson::object entryObject;
|
|
entryObject["map_section"] = section;
|
|
entryObject["name"] = entry.name;
|
|
entryObject["x"] = entry.x;
|
|
entryObject["y"] = entry.y;
|
|
entryObject["width"] = entry.width;
|
|
entryObject["height"] = entry.height;
|
|
|
|
mapSectionArray.append(entryObject);
|
|
}
|
|
|
|
object["map_sections"] = mapSectionArray;
|
|
|
|
OrderedJson sectionsJson(object);
|
|
OrderedJsonDoc jsonDoc(§ionsJson);
|
|
jsonDoc.dump(§ionsFile);
|
|
sectionsFile.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
void buildEmeraldDefaults(poryjson::Json &json) {
|
|
ParseUtil parser;
|
|
QString emeraldDefault = parser.readTextFile(":/text/region_map_default_emerald.json");
|
|
|
|
QString err;
|
|
json = poryjson::Json::parse(emeraldDefault, err);
|
|
}
|
|
|
|
void buildRubyDefaults(poryjson::Json &json) {
|
|
ParseUtil parser;
|
|
QString emeraldDefault = parser.readTextFile(":/text/region_map_default_ruby.json");
|
|
|
|
QString err;
|
|
json = poryjson::Json::parse(emeraldDefault, err);
|
|
}
|
|
|
|
void buildFireredDefaults(poryjson::Json &json) {
|
|
|
|
ParseUtil parser;
|
|
QString fireredDefault = parser.readTextFile(":/text/region_map_default_firered.json");
|
|
|
|
QString err;
|
|
json = poryjson::Json::parse(fireredDefault, err);
|
|
}
|
|
|
|
poryjson::Json RegionMapEditor::buildDefaultJson() {
|
|
poryjson::Json defaultJson;
|
|
switch (projectConfig.getBaseGameVersion()) {
|
|
case BaseGameVersion::pokeemerald:
|
|
buildEmeraldDefaults(defaultJson);
|
|
break;
|
|
|
|
case BaseGameVersion::pokeruby:
|
|
buildRubyDefaults(defaultJson);
|
|
break;
|
|
|
|
case BaseGameVersion::pokefirered:
|
|
buildFireredDefaults(defaultJson);
|
|
break;
|
|
}
|
|
|
|
return defaultJson;
|
|
}
|
|
|
|
bool RegionMapEditor::buildConfigDialog() {
|
|
// use this temporary object while window is active, save only when user accepts
|
|
poryjson::Json rmConfigJsonUpdate = this->rmConfigJson;
|
|
|
|
QDialog dialog(this);
|
|
dialog.setWindowTitle("Configure Region Maps");
|
|
dialog.setWindowModality(Qt::WindowModal);
|
|
|
|
QFormLayout form(&dialog);
|
|
|
|
// need to display current region map(s) if there are some
|
|
QListWidget *regionMapList = new QListWidget(&dialog);
|
|
|
|
form.addRow(new QLabel("Region Map List:"));
|
|
form.addRow(regionMapList);
|
|
|
|
// lambda to update the current map list displayed in the config window with a
|
|
// widget item that contains that region map's json data
|
|
auto updateMapList = [regionMapList, &rmConfigJsonUpdate]() {
|
|
regionMapList->clear();
|
|
poryjson::Json::object mapsObject = rmConfigJsonUpdate.object_items();
|
|
for (auto o : mapsObject["region_maps"].array_items()) {
|
|
poryjson::Json::object object = o.object_items();
|
|
QListWidgetItem *newItem = new QListWidgetItem;
|
|
newItem->setText(object["alias"].string_value());
|
|
QString objectString;
|
|
int i = 0;
|
|
o.dump(objectString, &i);
|
|
newItem->setData(Qt::UserRole, objectString);
|
|
regionMapList->addItem(newItem);
|
|
}
|
|
};
|
|
updateMapList();
|
|
|
|
auto updateJsonFromList = [regionMapList, &rmConfigJsonUpdate]() {
|
|
poryjson::Json::object newJson;
|
|
poryjson::Json::array mapArr;
|
|
for (auto item : regionMapList->findItems("*", Qt::MatchWildcard)) {
|
|
QString err;
|
|
poryjson::Json itemJson = poryjson::Json::parse(item->data(Qt::UserRole).toString(), err);
|
|
mapArr.append(itemJson);
|
|
}
|
|
newJson["region_maps"] = mapArr;
|
|
rmConfigJsonUpdate = poryjson::Json(newJson);
|
|
};
|
|
|
|
// when double clicking a region map from the list, bring up the configuration window
|
|
// and populate it with the current values
|
|
// the user can edit and save the config for an existing map this way
|
|
connect(regionMapList, &QListWidget::itemDoubleClicked, [this, &rmConfigJsonUpdate, updateMapList, regionMapList](QListWidgetItem *item) {
|
|
int itemIndex = regionMapList->row(item);
|
|
|
|
QString err;
|
|
poryjson::Json clickedJson = poryjson::Json::parse(item->data(Qt::UserRole).toString(), err);
|
|
|
|
RegionMapPropertiesDialog dialog(this);
|
|
dialog.setProject(this->project);
|
|
|
|
// populate
|
|
dialog.setProperties(clickedJson);
|
|
|
|
if (dialog.exec() == QDialog::Accepted) {
|
|
// update the object then update the map list
|
|
poryjson::Json updatedMap = dialog.saveToJson();
|
|
poryjson::Json::object previousObj = rmConfigJsonUpdate.object_items();
|
|
poryjson::Json::array newMapList = previousObj["region_maps"].array_items(); // copy
|
|
newMapList[itemIndex] = updatedMap;
|
|
previousObj["region_maps"] = newMapList;
|
|
rmConfigJsonUpdate = poryjson::Json(previousObj);
|
|
|
|
updateMapList();
|
|
}
|
|
});
|
|
|
|
QPushButton *addMapButton = new QPushButton("Add Region Map...");
|
|
form.addRow(addMapButton);
|
|
|
|
// allow user to add region maps
|
|
connect(addMapButton, &QPushButton::clicked, [this, regionMapList] {
|
|
poryjson::Json resultJson = configRegionMapDialog();
|
|
poryjson::Json::object resultObj = resultJson.object_items();
|
|
|
|
QString resultStr;
|
|
int tab = 0;
|
|
resultJson.dump(resultStr, &tab);
|
|
|
|
QListWidgetItem *newItem = new QListWidgetItem;
|
|
newItem->setText(resultObj["alias"].string_value());
|
|
newItem->setData(Qt::UserRole, resultStr);
|
|
regionMapList->addItem(newItem);
|
|
});
|
|
|
|
QPushButton *delMapButton = new QPushButton("Delete Selected Region Map");
|
|
form.addRow(delMapButton);
|
|
|
|
connect(delMapButton, &QPushButton::clicked, [this, regionMapList, &updateJsonFromList] {
|
|
QListWidgetItem *item = regionMapList->currentItem();
|
|
if (item) {
|
|
regionMapList->removeItemWidget(item);
|
|
delete item;
|
|
updateJsonFromList();
|
|
}
|
|
});
|
|
|
|
// TODO: city maps (leaving this for now)
|
|
// QListWidget *cityMapList = new QListWidget(&dialog);
|
|
// // TODO: double clicking can delete them? bring up the tiny menu thing like sory by maps
|
|
// //cityMapList->setSelectionMode(QAbstractItemView::NoSelection);
|
|
// //cityMapList->setFocusPolicy(Qt::NoFocus);
|
|
// form.addRow(new QLabel("City Map List:"));
|
|
// form.addRow(cityMapList);
|
|
//
|
|
// for (int i = 0; i < 20; i++) {
|
|
// QListWidgetItem *newItem = new QListWidgetItem;
|
|
// newItem->setText(QString("city %1").arg(i));
|
|
// cityMapList->addItem(newItem);
|
|
// }
|
|
//
|
|
// QPushButton *addCitiesButton = new QPushButton("Configure City Maps...");
|
|
// form.addRow(addCitiesButton);
|
|
// // needs to pick tilemaps and such here too
|
|
|
|
|
|
// for sake of convenience, option to just use defaults for each basegame version
|
|
QPushButton *config_useProjectDefault;
|
|
switch (projectConfig.getBaseGameVersion()) {
|
|
case BaseGameVersion::pokefirered:
|
|
config_useProjectDefault = new QPushButton("\nUse pokefirered defaults\n");
|
|
break;
|
|
case BaseGameVersion::pokeemerald:
|
|
config_useProjectDefault = new QPushButton("\nUse pokeemerald defaults\n");
|
|
break;
|
|
case BaseGameVersion::pokeruby:
|
|
config_useProjectDefault = new QPushButton("\nUse pokeruby defaults\n");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
form.addRow(config_useProjectDefault);
|
|
|
|
connect(config_useProjectDefault, &QPushButton::clicked, [this, &rmConfigJsonUpdate, updateMapList](){
|
|
poryjson::Json newJson = buildDefaultJson();
|
|
// no error checking required because these are well-formed files
|
|
rmConfigJsonUpdate = newJson;
|
|
updateMapList();
|
|
});
|
|
|
|
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
|
|
connect(&buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
|
connect(&buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
|
|
|
form.addRow(&buttonBox);
|
|
|
|
if (dialog.exec() == QDialog::Accepted) {
|
|
// if everything looks good, we can update the master json
|
|
this->rmConfigJson = rmConfigJsonUpdate;
|
|
this->configSaved = false;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
poryjson::Json RegionMapEditor::configRegionMapDialog() {
|
|
|
|
RegionMapPropertiesDialog dialog(this);
|
|
dialog.setProject(this->project);
|
|
|
|
if (dialog.exec() == QDialog::Accepted) {
|
|
poryjson::Json regionMapJson = dialog.saveToJson();
|
|
return regionMapJson;
|
|
}
|
|
|
|
return poryjson::Json();
|
|
}
|
|
|
|
bool RegionMapEditor::verifyConfig(poryjson::Json cfg) {
|
|
OrderedJson::object obj = cfg.object_items();
|
|
|
|
if (!obj.contains("region_maps")) {
|
|
logError("Region map config json has no map list.");
|
|
return false;
|
|
}
|
|
|
|
OrderedJson::array arr = obj["region_maps"].array_items();
|
|
|
|
for (auto ref : arr) {
|
|
RegionMap tempMap(this->project);
|
|
if (!tempMap.loadMapData(ref)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void RegionMapEditor::clear() {
|
|
// clear everything that gets loaded in a way that will not crash the destructor
|
|
// except the config json
|
|
|
|
auto stacks = this->history.stacks();
|
|
this->history.blockSignals(true);
|
|
for (auto *stack : stacks) {
|
|
this->history.removeStack(stack);
|
|
}
|
|
this->history.blockSignals(false);
|
|
for (auto p : this->region_maps) {
|
|
delete p.second;
|
|
}
|
|
this->region_map = nullptr;
|
|
this->region_maps.clear();
|
|
this->region_map_entries.clear();
|
|
|
|
this->currIndex = 0;
|
|
this->activeEntry = QString();
|
|
this->entriesFirstDraw = true;
|
|
|
|
delete region_map_item;
|
|
region_map_item = nullptr;
|
|
|
|
delete mapsquare_selector_item;
|
|
mapsquare_selector_item = nullptr;
|
|
|
|
delete region_map_layout_item;
|
|
region_map_layout_item = nullptr;
|
|
|
|
delete scene_region_map_image;
|
|
scene_region_map_image = nullptr;
|
|
|
|
delete scene_region_map_layout;
|
|
scene_region_map_layout = nullptr;
|
|
|
|
delete scene_region_map_tiles;
|
|
scene_region_map_tiles = nullptr;
|
|
}
|
|
|
|
bool RegionMapEditor::reload() {
|
|
clear();
|
|
return setup();
|
|
}
|
|
|
|
bool RegionMapEditor::setup() {
|
|
// if all has gone well, this->rmConfigJson should be populated
|
|
// next, load the entries
|
|
loadRegionMapEntries();
|
|
|
|
// load the region maps into this->region_maps
|
|
poryjson::Json::object regionMapObjectCopy = this->rmConfigJson.object_items();
|
|
for (auto o : regionMapObjectCopy["region_maps"].array_items()) {
|
|
QString alias = o.object_items().at("alias").string_value();
|
|
|
|
RegionMap *newMap = new RegionMap(this->project);
|
|
newMap->setEntries(&this->region_map_entries);
|
|
if (!newMap->loadMapData(o)) {
|
|
delete newMap;
|
|
// TODO: consider continue, just reporting error loading single map?
|
|
return false;
|
|
}
|
|
|
|
connect(newMap, &RegionMap::mapNeedsDisplaying, [this]() {
|
|
displayRegionMap();
|
|
});
|
|
|
|
region_maps[alias] = newMap;
|
|
|
|
this->history.addStack(&(newMap->editHistory));
|
|
}
|
|
|
|
// add to ui
|
|
this->ui->comboBox_regionSelector->clear();
|
|
for (auto p : region_maps) {
|
|
this->ui->comboBox_regionSelector->addItem(p.first);
|
|
}
|
|
|
|
// display the first region map in the list
|
|
if (!region_maps.empty()) {
|
|
setRegionMap(region_maps.begin()->second);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RegionMapEditor::load(bool silent) {
|
|
// check for config json file
|
|
QString jsonConfigFilepath = this->project->root + "/" + projectConfig.getFilePath(ProjectFilePath::json_region_porymap_cfg);
|
|
|
|
bool badConfig = true;
|
|
|
|
if (QFile::exists(jsonConfigFilepath)) {
|
|
logInfo("Region map configuration file found.");
|
|
ParseUtil parser;
|
|
OrderedJson::object obj;
|
|
if (parser.tryParseOrderedJsonFile(&obj, jsonConfigFilepath)) {
|
|
this->rmConfigJson = OrderedJson(obj);
|
|
this->configSaved = true;
|
|
}
|
|
badConfig = !verifyConfig(this->rmConfigJson);
|
|
} else {
|
|
logWarn("Region Map config file not found.");
|
|
}
|
|
|
|
if (badConfig) {
|
|
if (silent) return false;
|
|
// show popup explaining next window
|
|
QMessageBox warning;
|
|
warning.setIcon(QMessageBox::Warning);
|
|
warning.setText("Region map configuration not found.");
|
|
warning.setInformativeText("In order to continue, you must setup porymap to use your region map.");
|
|
warning.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
|
warning.setDefaultButton(QMessageBox::Ok);
|
|
|
|
if (warning.exec() == QMessageBox::Ok) {
|
|
// there is a separate window that allows to load multiple region maps,
|
|
if (!buildConfigDialog()) {
|
|
logError("Region map loading interrupted [user]");
|
|
return false;
|
|
}
|
|
} else {
|
|
// do not open editor
|
|
logError("Region map loading interrupted [user]");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return setup();
|
|
}
|
|
|
|
void RegionMapEditor::setRegionMap(RegionMap *map) {
|
|
this->region_map = map;
|
|
this->currIndex = this->region_map->firstLayoutIndex();
|
|
|
|
if (this->region_map->layoutEnabled()) {
|
|
this->ui->tabWidget_Region_Map->setTabEnabled(1, true);
|
|
this->ui->tabWidget_Region_Map->setTabEnabled(2, true);
|
|
} else {
|
|
this->ui->tabWidget_Region_Map->setTabEnabled(1, false);
|
|
this->ui->tabWidget_Region_Map->setTabEnabled(2, false);
|
|
this->ui->tabWidget_Region_Map->setCurrentIndex(0);
|
|
}
|
|
|
|
displayRegionMap();
|
|
this->region_map->editHistory.setActive();
|
|
}
|
|
|
|
bool RegionMapEditor::saveRegionMap(RegionMap *map) {
|
|
if (!map) return false;
|
|
|
|
map->save();
|
|
|
|
return true;
|
|
}
|
|
|
|
void RegionMapEditor::saveConfig() {
|
|
OrderedJson::array mapArray;
|
|
for (auto it : this->region_maps) {
|
|
OrderedJson::object obj = it.second->config();
|
|
mapArray.append(obj);
|
|
}
|
|
|
|
OrderedJson::object mapsObject;
|
|
mapsObject["region_maps"] = mapArray;
|
|
|
|
OrderedJson newConfigJson(mapsObject);
|
|
QString filepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_porymap_cfg));
|
|
QFile file(filepath);
|
|
if (!file.open(QIODevice::WriteOnly)) {
|
|
logError(QString("Error: Could not open %1 for writing").arg(filepath));
|
|
return;
|
|
}
|
|
OrderedJsonDoc jsonDoc(&newConfigJson);
|
|
jsonDoc.dump(&file);
|
|
file.close();
|
|
|
|
this->configSaved = true;
|
|
}
|
|
|
|
void RegionMapEditor::on_action_RegionMap_Save_triggered() {
|
|
saveRegionMap(this->region_map);
|
|
|
|
// save entries
|
|
saveRegionMapEntries();
|
|
|
|
// save config
|
|
saveConfig();
|
|
}
|
|
|
|
void RegionMapEditor::on_actionSave_All_triggered() {
|
|
for (auto it : this->region_maps) {
|
|
saveRegionMap(it.second);
|
|
}
|
|
saveRegionMapEntries();
|
|
saveConfig();
|
|
}
|
|
|
|
void RegionMapEditor::on_action_Configure_triggered() {
|
|
if (this->modified()) {
|
|
QMessageBox warning;
|
|
warning.setIcon(QMessageBox::Warning);
|
|
warning.setText("Reconfiguring region maps will discard any unsaved changes.");
|
|
warning.setInformativeText("Continue?");
|
|
warning.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
|
warning.setDefaultButton(QMessageBox::Ok);
|
|
|
|
if (warning.exec() == QMessageBox::Ok) {
|
|
if (buildConfigDialog()) {
|
|
reload();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (buildConfigDialog()) {
|
|
reload();
|
|
}
|
|
}
|
|
}
|
|
|
|
void RegionMapEditor::displayRegionMap() {
|
|
displayRegionMapTileSelector();
|
|
displayRegionMapImage();
|
|
displayRegionMapLayout();
|
|
displayRegionMapLayoutOptions();
|
|
displayRegionMapEntriesImage();
|
|
displayRegionMapEntryOptions();
|
|
|
|
updateLayerDisplayed();
|
|
}
|
|
|
|
void RegionMapEditor::updateLayerDisplayed() {
|
|
// add layers from layout to combo
|
|
ui->comboBox_layoutLayer->clear();
|
|
ui->comboBox_layoutLayer->addItems(this->region_map->getLayers());
|
|
}
|
|
|
|
void RegionMapEditor::on_comboBox_regionSelector_textActivated(const QString ®ion) {
|
|
if (this->region_maps.contains(region)) {
|
|
setRegionMap(region_maps.at(region));
|
|
}
|
|
}
|
|
|
|
void RegionMapEditor::displayRegionMapImage() {
|
|
if (!scene_region_map_image) {
|
|
this->scene_region_map_image = new QGraphicsScene;
|
|
}
|
|
if (region_map_item && scene_region_map_image) {
|
|
scene_region_map_image->removeItem(region_map_item);
|
|
delete region_map_item;
|
|
}
|
|
|
|
this->region_map_item = new RegionMapPixmapItem(this->region_map, this->mapsquare_selector_item);
|
|
this->region_map_item->draw();
|
|
|
|
connect(this->region_map_item, &RegionMapPixmapItem::mouseEvent,
|
|
this, &RegionMapEditor::mouseEvent_region_map);
|
|
connect(this->region_map_item, &RegionMapPixmapItem::hoveredRegionMapTileChanged,
|
|
this, &RegionMapEditor::onHoveredRegionMapTileChanged);
|
|
connect(this->region_map_item, &RegionMapPixmapItem::hoveredRegionMapTileCleared,
|
|
this, &RegionMapEditor::onHoveredRegionMapTileCleared);
|
|
|
|
this->scene_region_map_image->addItem(this->region_map_item);
|
|
this->scene_region_map_image->setSceneRect(this->scene_region_map_image->itemsBoundingRect());
|
|
|
|
this->ui->graphicsView_Region_Map_BkgImg->setScene(this->scene_region_map_image);
|
|
|
|
on_verticalSlider_Zoom_Map_Image_valueChanged(this->ui->verticalSlider_Zoom_Map_Image->value());
|
|
}
|
|
|
|
void RegionMapEditor::displayRegionMapLayout() {
|
|
if (!scene_region_map_layout) {
|
|
this->scene_region_map_layout = new QGraphicsScene;
|
|
}
|
|
if (region_map_layout_item && scene_region_map_layout) {
|
|
this->scene_region_map_layout->removeItem(region_map_layout_item);
|
|
delete region_map_layout_item;
|
|
}
|
|
|
|
this->region_map_layout_item = new RegionMapLayoutPixmapItem(this->region_map, this->mapsquare_selector_item);
|
|
|
|
connect(this->region_map_layout_item, &RegionMapLayoutPixmapItem::selectedTileChanged,
|
|
this, &RegionMapEditor::onRegionMapLayoutSelectedTileChanged);
|
|
connect(this->region_map_layout_item, &RegionMapLayoutPixmapItem::hoveredTileChanged,
|
|
this, &RegionMapEditor::onRegionMapLayoutHoveredTileChanged);
|
|
connect(this->region_map_layout_item, &RegionMapLayoutPixmapItem::hoveredTileCleared,
|
|
this, &RegionMapEditor::onRegionMapLayoutHoveredTileCleared);
|
|
|
|
this->region_map_layout_item->draw();
|
|
this->region_map_layout_item->select(this->currIndex);
|
|
|
|
this->scene_region_map_layout->addItem(region_map_layout_item);
|
|
this->scene_region_map_layout->setSceneRect(this->scene_region_map_layout->itemsBoundingRect());
|
|
|
|
this->ui->graphicsView_Region_Map_Layout->setScene(this->scene_region_map_layout);
|
|
}
|
|
|
|
void RegionMapEditor::displayRegionMapLayoutOptions() {
|
|
if (!this->region_map->layoutEnabled()) return;
|
|
|
|
this->ui->comboBox_RM_ConnectedMap->blockSignals(true);
|
|
this->ui->comboBox_RM_ConnectedMap->clear();
|
|
this->ui->comboBox_RM_ConnectedMap->addItems(this->project->mapSectionValueToName.values());
|
|
this->ui->comboBox_RM_ConnectedMap->blockSignals(false);
|
|
|
|
this->ui->frame_RM_Options->setEnabled(true);
|
|
|
|
updateRegionMapLayoutOptions(this->currIndex);
|
|
}
|
|
|
|
void RegionMapEditor::updateRegionMapLayoutOptions(int index) {
|
|
this->ui->comboBox_RM_ConnectedMap->blockSignals(true);
|
|
this->ui->comboBox_RM_ConnectedMap->setCurrentText(this->region_map->squareMapSection(index));
|
|
this->ui->comboBox_RM_ConnectedMap->blockSignals(false);
|
|
|
|
this->ui->pushButton_RM_Options_delete->setEnabled(this->region_map->squareHasMap(index));
|
|
|
|
this->ui->spinBox_RM_LayoutWidth->blockSignals(true);
|
|
this->ui->spinBox_RM_LayoutHeight->blockSignals(true);
|
|
this->ui->spinBox_RM_LayoutWidth->setMinimum(1);
|
|
this->ui->spinBox_RM_LayoutWidth->setMaximum(this->region_map->tilemapWidth() - this->region_map->padLeft());
|
|
this->ui->spinBox_RM_LayoutHeight->setMinimum(1);
|
|
this->ui->spinBox_RM_LayoutHeight->setMaximum(this->region_map->tilemapHeight() - this->region_map->padTop());
|
|
this->ui->spinBox_RM_LayoutWidth->setValue(this->region_map->layoutWidth());
|
|
this->ui->spinBox_RM_LayoutHeight->setValue(this->region_map->layoutHeight());
|
|
this->ui->spinBox_RM_LayoutWidth->blockSignals(false);
|
|
this->ui->spinBox_RM_LayoutHeight->blockSignals(false);
|
|
}
|
|
|
|
void RegionMapEditor::displayRegionMapEntriesImage() {
|
|
if (!scene_region_map_entries) {
|
|
this->scene_region_map_entries = new QGraphicsScene;
|
|
}
|
|
if (region_map_entries_item && scene_region_map_entries) {
|
|
this->scene_region_map_entries->removeItem(region_map_entries_item);
|
|
delete region_map_entries_item;
|
|
}
|
|
|
|
this->region_map_entries_item = new RegionMapEntriesPixmapItem(this->region_map, this->mapsquare_selector_item);
|
|
|
|
connect(this->region_map_entries_item, &RegionMapEntriesPixmapItem::entryPositionChanged,
|
|
this, &RegionMapEditor::onRegionMapEntryDragged);
|
|
|
|
if (entriesFirstDraw) {
|
|
QString first = this->ui->comboBox_RM_Entry_MapSection->currentText();
|
|
this->region_map_entries_item->currentSection = first;
|
|
this->activeEntry = first;
|
|
updateRegionMapEntryOptions(first);
|
|
entriesFirstDraw = false;
|
|
}
|
|
|
|
this->region_map_entries_item->draw();
|
|
|
|
int idx = this->region_map_entries.contains(activeEntry) ? this->region_map->getMapSquareIndex(this->region_map_entries[activeEntry].x + this->region_map->padLeft(),
|
|
this->region_map_entries[activeEntry].y + this->region_map->padTop())
|
|
: 0;
|
|
this->region_map_entries_item->select(idx);
|
|
|
|
|
|
this->scene_region_map_entries->addItem(region_map_entries_item);
|
|
this->scene_region_map_entries->setSceneRect(this->scene_region_map_entries->itemsBoundingRect());
|
|
|
|
this->ui->graphicsView_Region_Map_Entries->setScene(this->scene_region_map_entries);
|
|
}
|
|
|
|
void RegionMapEditor::displayRegionMapEntryOptions() {
|
|
if (!this->region_map->layoutEnabled()) return;
|
|
|
|
this->ui->comboBox_RM_Entry_MapSection->clear();
|
|
this->ui->comboBox_RM_Entry_MapSection->addItems(this->project->mapSectionValueToName.values());
|
|
this->ui->spinBox_RM_Entry_x->setMaximum(128);
|
|
this->ui->spinBox_RM_Entry_y->setMaximum(128);
|
|
this->ui->spinBox_RM_Entry_width->setMinimum(1);
|
|
this->ui->spinBox_RM_Entry_height->setMinimum(1);
|
|
this->ui->spinBox_RM_Entry_width->setMaximum(128);
|
|
this->ui->spinBox_RM_Entry_height->setMaximum(128);
|
|
}
|
|
|
|
void RegionMapEditor::updateRegionMapEntryOptions(QString section) {
|
|
if (!this->region_map->layoutEnabled()) return;
|
|
|
|
bool isSpecialSection = (section == this->region_map->default_map_section
|
|
|| section == this->region_map->count_map_section);
|
|
|
|
bool enabled = (!isSpecialSection && this->region_map_entries.contains(section));
|
|
|
|
this->ui->lineEdit_RM_MapName->setEnabled(enabled);
|
|
this->ui->spinBox_RM_Entry_x->setEnabled(enabled);
|
|
this->ui->spinBox_RM_Entry_y->setEnabled(enabled);
|
|
this->ui->spinBox_RM_Entry_width->setEnabled(enabled);
|
|
this->ui->spinBox_RM_Entry_height->setEnabled(enabled);
|
|
this->ui->pushButton_entryActivate->setEnabled(!isSpecialSection);
|
|
this->ui->pushButton_entryActivate->setText(enabled ? "Remove" : "Add");
|
|
|
|
this->ui->lineEdit_RM_MapName->blockSignals(true);
|
|
this->ui->spinBox_RM_Entry_x->blockSignals(true);
|
|
this->ui->spinBox_RM_Entry_y->blockSignals(true);
|
|
this->ui->spinBox_RM_Entry_width->blockSignals(true);
|
|
this->ui->spinBox_RM_Entry_height->blockSignals(true);
|
|
|
|
this->ui->comboBox_RM_Entry_MapSection->setCurrentText(section);
|
|
this->activeEntry = section;
|
|
this->region_map_entries_item->currentSection = section;
|
|
MapSectionEntry entry = enabled ? this->region_map_entries[section] : MapSectionEntry();
|
|
this->ui->lineEdit_RM_MapName->setText(entry.name);
|
|
this->ui->spinBox_RM_Entry_x->setValue(entry.x);
|
|
this->ui->spinBox_RM_Entry_y->setValue(entry.y);
|
|
this->ui->spinBox_RM_Entry_width->setValue(entry.width);
|
|
this->ui->spinBox_RM_Entry_height->setValue(entry.height);
|
|
|
|
this->ui->lineEdit_RM_MapName->blockSignals(false);
|
|
this->ui->spinBox_RM_Entry_x->blockSignals(false);
|
|
this->ui->spinBox_RM_Entry_y->blockSignals(false);
|
|
this->ui->spinBox_RM_Entry_width->blockSignals(false);
|
|
this->ui->spinBox_RM_Entry_height->blockSignals(false);
|
|
}
|
|
|
|
void RegionMapEditor::on_pushButton_entryActivate_clicked() {
|
|
QString section = this->ui->comboBox_RM_Entry_MapSection->currentText();
|
|
if (section == this->region_map->default_map_section) return;
|
|
|
|
if (this->region_map_entries.contains(section)) {
|
|
// disable
|
|
MapSectionEntry oldEntry = this->region_map->getEntry(section);
|
|
this->region_map->removeEntry(section);
|
|
MapSectionEntry newEntry = this->region_map->getEntry(section);
|
|
RemoveEntry *commit = new RemoveEntry(this->region_map, section, oldEntry, newEntry);
|
|
this->region_map->editHistory.push(commit);
|
|
updateRegionMapEntryOptions(section);
|
|
|
|
this->ui->pushButton_entryActivate->setText("Add");
|
|
} else {
|
|
// enable
|
|
MapSectionEntry oldEntry = this->region_map->getEntry(section);
|
|
MapSectionEntry entry = MapSectionEntry();
|
|
entry.valid = true;
|
|
this->region_map->setEntry(section, entry);
|
|
MapSectionEntry newEntry = this->region_map->getEntry(section);
|
|
AddEntry *commit = new AddEntry(this->region_map, section, oldEntry, newEntry);
|
|
this->region_map->editHistory.push(commit);
|
|
updateRegionMapEntryOptions(section);
|
|
|
|
this->ui->pushButton_entryActivate->setText("Remove");
|
|
}
|
|
}
|
|
|
|
void RegionMapEditor::displayRegionMapTileSelector() {
|
|
if (!scene_region_map_tiles) {
|
|
this->scene_region_map_tiles = new QGraphicsScene;
|
|
}
|
|
if (mapsquare_selector_item && scene_region_map_tiles) {
|
|
this->scene_region_map_tiles->removeItem(mapsquare_selector_item);
|
|
delete mapsquare_selector_item;
|
|
}
|
|
|
|
this->mapsquare_selector_item = new TilemapTileSelector(this->region_map->pngPath(), this->region_map->tilemapFormat(), this->region_map->palPath());
|
|
|
|
this->mapsquare_selector_item->draw();
|
|
|
|
this->scene_region_map_tiles->addItem(this->mapsquare_selector_item);
|
|
|
|
connect(this->mapsquare_selector_item, &TilemapTileSelector::selectedTileChanged,
|
|
this, &RegionMapEditor::onRegionMapTileSelectorSelectedTileChanged);
|
|
connect(this->mapsquare_selector_item, &TilemapTileSelector::hoveredTileChanged,
|
|
this, &RegionMapEditor::onRegionMapTileSelectorHoveredTileChanged);
|
|
connect(this->mapsquare_selector_item, &TilemapTileSelector::hoveredTileCleared,
|
|
this, &RegionMapEditor::onRegionMapTileSelectorHoveredTileCleared);
|
|
|
|
this->ui->graphicsView_RegionMap_Tiles->setScene(this->scene_region_map_tiles);
|
|
on_verticalSlider_Zoom_Image_Tiles_valueChanged(this->ui->verticalSlider_Zoom_Image_Tiles->value());
|
|
|
|
this->ui->frame_tileOptions->setEnabled(this->region_map->tilemapFormat() != TilemapFormat::Plain);
|
|
|
|
this->mapsquare_selector_item->select(this->selectedImageTile);
|
|
}
|
|
|
|
void RegionMapEditor::onRegionMapTileSelectorSelectedTileChanged(unsigned id) {
|
|
this->selectedImageTile = id;
|
|
}
|
|
|
|
void RegionMapEditor::onRegionMapTileSelectorHoveredTileChanged(unsigned tileId) {
|
|
QString message = QString("Tile: 0x") + QString("%1").arg(tileId, 4, 16, QChar('0')).toUpper();
|
|
this->ui->statusbar->showMessage(message);
|
|
}
|
|
|
|
void RegionMapEditor::onRegionMapTileSelectorHoveredTileCleared() {
|
|
this->ui->statusbar->clearMessage();
|
|
}
|
|
|
|
void RegionMapEditor::onRegionMapEntryDragged(int new_x, int new_y) {
|
|
on_spinBox_RM_Entry_x_valueChanged(new_x);
|
|
on_spinBox_RM_Entry_y_valueChanged(new_y);
|
|
updateRegionMapEntryOptions(activeEntry);
|
|
}
|
|
|
|
void RegionMapEditor::onRegionMapLayoutSelectedTileChanged(int index) {
|
|
QString message = QString();
|
|
this->currIndex = index;
|
|
this->region_map_layout_item->highlightedTile = index;
|
|
if (this->region_map->squareHasMap(index)) {
|
|
message = QString("\t %1").arg(this->project->mapSecToMapHoverName.value(
|
|
this->region_map->squareMapSection(index))).remove("{NAME_END}");
|
|
}
|
|
this->ui->statusbar->showMessage(message);
|
|
|
|
updateRegionMapLayoutOptions(index);
|
|
this->region_map_layout_item->draw();
|
|
}
|
|
|
|
void RegionMapEditor::onRegionMapLayoutHoveredTileChanged(int index) {
|
|
QString message = QString();
|
|
int x = this->region_map->squareX(index);
|
|
int y = this->region_map->squareY(index);
|
|
if (x >= 0 && y >= 0) {
|
|
message = QString("(%1, %2)").arg(x).arg(y);
|
|
if (this->region_map->squareHasMap(index)) {
|
|
message += QString("\t %1").arg(this->project->mapSecToMapHoverName.value(
|
|
this->region_map->squareMapSection(index))).remove("{NAME_END}");
|
|
}
|
|
}
|
|
this->ui->statusbar->showMessage(message);
|
|
}
|
|
|
|
void RegionMapEditor::onRegionMapLayoutHoveredTileCleared() {
|
|
this->ui->statusbar->clearMessage();
|
|
}
|
|
|
|
void RegionMapEditor::onHoveredRegionMapTileChanged(int x, int y) {
|
|
shared_ptr<TilemapTile> tile = this->region_map->getTile(x, y);
|
|
QString message = QString("x: %1, y: %2 ").arg(x).arg(y) + tile->info();
|
|
this->ui->statusbar->showMessage(message);
|
|
}
|
|
|
|
void RegionMapEditor::onHoveredRegionMapTileCleared() {
|
|
this->ui->statusbar->clearMessage();
|
|
}
|
|
|
|
void RegionMapEditor::mouseEvent_region_map(QGraphicsSceneMouseEvent *event, RegionMapPixmapItem *item) {
|
|
static unsigned actionId_ = 0;
|
|
|
|
QPointF pos = event->pos();
|
|
int x = static_cast<int>(pos.x()) / 8;
|
|
int y = static_cast<int>(pos.y()) / 8;
|
|
int index = this->region_map->getMapSquareIndex(x, y);
|
|
if (index > this->region_map->tilemapSize() - 1) return; // TODO: is the math correct here?
|
|
|
|
if (event->buttons() & Qt::RightButton) {
|
|
item->select(event);
|
|
// set palette and flips
|
|
auto tile = this->region_map->getTile(x, y);
|
|
this->ui->spinBox_tilePalette->setValue(tile->palette());
|
|
this->ui->checkBox_tileHFlip->setChecked(tile->hFlip());
|
|
this->ui->checkBox_tileVFlip->setChecked(tile->vFlip());
|
|
} else if (event->modifiers() & Qt::ControlModifier) {
|
|
if (event->type() == QEvent::GraphicsSceneMouseRelease) {
|
|
actionId_++;
|
|
} else {
|
|
QByteArray oldTilemap = this->region_map->getTilemap();
|
|
item->fill(event);
|
|
QByteArray newTilemap = this->region_map->getTilemap();
|
|
EditTilemap *command = new EditTilemap(this->region_map, oldTilemap, newTilemap, actionId_);
|
|
command->setText("Fill Tilemap");
|
|
this->region_map->commit(command);
|
|
}
|
|
} else {
|
|
if (event->type() == QEvent::GraphicsSceneMouseRelease) {
|
|
actionId_++;
|
|
} else {
|
|
QByteArray oldTilemap = this->region_map->getTilemap();
|
|
item->paint(event);
|
|
QByteArray newTilemap = this->region_map->getTilemap();
|
|
EditTilemap *command = new EditTilemap(this->region_map, oldTilemap, newTilemap, actionId_);
|
|
this->region_map->commit(command);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RegionMapEditor::on_tabWidget_Region_Map_currentChanged(int index) {
|
|
this->ui->stackedWidget_RM_Options->setCurrentIndex(index);
|
|
if (!this->region_map) return;
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
this->ui->verticalSlider_Zoom_Image_Tiles->setVisible(true);
|
|
if (this->region_map_item)
|
|
this->region_map_item->draw();
|
|
break;
|
|
case 1:
|
|
this->ui->verticalSlider_Zoom_Image_Tiles->setVisible(false);
|
|
if (this->region_map_layout_item) {
|
|
this->region_map_layout_item->draw();
|
|
updateRegionMapLayoutOptions(this->currIndex);
|
|
}
|
|
break;
|
|
case 2:
|
|
this->ui->verticalSlider_Zoom_Image_Tiles->setVisible(false);
|
|
on_comboBox_RM_Entry_MapSection_textActivated(ui->comboBox_RM_Entry_MapSection->currentText());
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RegionMapEditor::on_comboBox_RM_ConnectedMap_textActivated(const QString &mapsec) {
|
|
QString layer = this->region_map->getLayer();
|
|
this->region_map->setSquareMapSection(this->currIndex, mapsec);
|
|
|
|
onRegionMapLayoutSelectedTileChanged(this->currIndex);// re-draw layout image
|
|
}
|
|
|
|
void RegionMapEditor::on_comboBox_RM_Entry_MapSection_textActivated(const QString &text) {
|
|
this->activeEntry = text;
|
|
this->region_map_entries_item->currentSection = text;
|
|
updateRegionMapEntryOptions(text);
|
|
|
|
if (!this->region_map_entries.contains(text)) {
|
|
this->region_map_entries_item->select(0);
|
|
this->region_map_entries_item->draw();
|
|
return;
|
|
}
|
|
int idx = this->region_map->getMapSquareIndex(this->region_map_entries[activeEntry].x + this->region_map->padLeft(),
|
|
this->region_map_entries[activeEntry].y + this->region_map->padTop());
|
|
|
|
this->region_map_entries_item->select(idx);
|
|
this->region_map_entries_item->draw();
|
|
}
|
|
|
|
void RegionMapEditor::on_comboBox_layoutLayer_textActivated(const QString &text) {
|
|
this->region_map->setLayer(text);
|
|
displayRegionMapLayout();
|
|
displayRegionMapLayoutOptions();
|
|
}
|
|
|
|
void RegionMapEditor::on_spinBox_RM_Entry_x_valueChanged(int x) {
|
|
if (!this->region_map_entries.contains(activeEntry)) return;
|
|
MapSectionEntry oldEntry = this->region_map_entries[activeEntry];
|
|
this->region_map_entries[activeEntry].x = x;
|
|
MapSectionEntry newEntry = this->region_map_entries[activeEntry];
|
|
EditEntry *commit = new EditEntry(this->region_map, activeEntry, oldEntry, newEntry);
|
|
this->region_map->editHistory.push(commit);
|
|
int idx = this->region_map->getMapSquareIndex(this->region_map_entries[activeEntry].x + this->region_map->padLeft(),
|
|
this->region_map_entries[activeEntry].y + this->region_map->padTop());
|
|
this->region_map_entries_item->select(idx);
|
|
this->region_map_entries_item->draw();
|
|
}
|
|
|
|
void RegionMapEditor::on_spinBox_RM_Entry_y_valueChanged(int y) {
|
|
if (!this->region_map_entries.contains(activeEntry)) return;
|
|
MapSectionEntry oldEntry = this->region_map_entries[activeEntry];
|
|
this->region_map_entries[activeEntry].y = y;
|
|
MapSectionEntry newEntry = this->region_map_entries[activeEntry];
|
|
EditEntry *commit = new EditEntry(this->region_map, activeEntry, oldEntry, newEntry);
|
|
this->region_map->editHistory.push(commit);
|
|
int idx = this->region_map->getMapSquareIndex(this->region_map_entries[activeEntry].x + this->region_map->padLeft(),
|
|
this->region_map_entries[activeEntry].y + this->region_map->padTop());
|
|
this->region_map_entries_item->select(idx);
|
|
this->region_map_entries_item->draw();
|
|
}
|
|
|
|
void RegionMapEditor::on_spinBox_RM_Entry_width_valueChanged(int width) {
|
|
if (!this->region_map_entries.contains(activeEntry)) return;
|
|
MapSectionEntry oldEntry = this->region_map_entries[activeEntry];
|
|
this->region_map_entries[activeEntry].width = width;
|
|
MapSectionEntry newEntry = this->region_map_entries[activeEntry];
|
|
EditEntry *commit = new EditEntry(this->region_map, activeEntry, oldEntry, newEntry);
|
|
this->region_map->editHistory.push(commit);
|
|
this->region_map_entries_item->draw();
|
|
}
|
|
|
|
void RegionMapEditor::on_spinBox_RM_Entry_height_valueChanged(int height) {
|
|
if (!this->region_map_entries.contains(activeEntry)) return;
|
|
MapSectionEntry oldEntry = this->region_map_entries[activeEntry];
|
|
this->region_map_entries[activeEntry].height = height;
|
|
MapSectionEntry newEntry = this->region_map_entries[activeEntry];
|
|
EditEntry *commit = new EditEntry(this->region_map, activeEntry, oldEntry, newEntry);
|
|
this->region_map->editHistory.push(commit);
|
|
this->region_map_entries_item->draw();
|
|
}
|
|
|
|
void RegionMapEditor::on_spinBox_RM_LayoutWidth_valueChanged(int value) {
|
|
if (this->region_map) {
|
|
int oldWidth = this->region_map->layoutWidth();
|
|
int oldHeight = this->region_map->layoutHeight();
|
|
QMap<QString, QList<LayoutSquare>> oldLayouts = this->region_map->getAllLayouts();
|
|
|
|
this->region_map->setLayoutDimensions(value, this->ui->spinBox_RM_LayoutHeight->value());
|
|
|
|
int newWidth = this->region_map->layoutWidth();
|
|
int newHeight = this->region_map->layoutHeight();
|
|
QMap<QString, QList<LayoutSquare>> newLayouts = this->region_map->getAllLayouts();
|
|
|
|
ResizeRMLayout *commit = new ResizeRMLayout(this->region_map, oldWidth, oldHeight, newWidth, newHeight, oldLayouts, newLayouts);
|
|
this->region_map->editHistory.push(commit);
|
|
}
|
|
}
|
|
|
|
void RegionMapEditor::on_spinBox_RM_LayoutHeight_valueChanged(int value) {
|
|
if (this->region_map) {
|
|
int oldWidth = this->region_map->layoutWidth();
|
|
int oldHeight = this->region_map->layoutHeight();
|
|
QMap<QString, QList<LayoutSquare>> oldLayouts = this->region_map->getAllLayouts();
|
|
|
|
this->region_map->setLayoutDimensions(this->ui->spinBox_RM_LayoutWidth->value(), value);
|
|
|
|
int newWidth = this->region_map->layoutWidth();
|
|
int newHeight = this->region_map->layoutHeight();
|
|
QMap<QString, QList<LayoutSquare>> newLayouts = this->region_map->getAllLayouts();
|
|
|
|
ResizeRMLayout *commit = new ResizeRMLayout(this->region_map, oldWidth, oldHeight, newWidth, newHeight, oldLayouts, newLayouts);
|
|
this->region_map->editHistory.push(commit);
|
|
}
|
|
}
|
|
|
|
void RegionMapEditor::on_lineEdit_RM_MapName_textEdited(const QString &text) {
|
|
if (!this->region_map_entries.contains(activeEntry)) return;
|
|
MapSectionEntry oldEntry = this->region_map_entries[activeEntry];
|
|
this->region_map_entries[activeEntry].name = text;
|
|
MapSectionEntry newEntry = this->region_map_entries[activeEntry];
|
|
EditEntry *commit = new EditEntry(this->region_map, activeEntry, oldEntry, newEntry);
|
|
this->region_map->editHistory.push(commit);
|
|
}
|
|
|
|
void RegionMapEditor::on_pushButton_RM_Options_delete_clicked() {
|
|
int index = this->region_map->tilemapToLayoutIndex(this->currIndex);
|
|
QList<LayoutSquare> oldLayout = this->region_map->getLayout(this->region_map->getLayer());
|
|
this->region_map->resetSquare(index);
|
|
QList<LayoutSquare> newLayout = this->region_map->getLayout(this->region_map->getLayer());
|
|
EditLayout *commit = new EditLayout(this->region_map, this->region_map->getLayer(), this->currIndex, oldLayout, newLayout);
|
|
commit->setText("Reset Layout Square");
|
|
this->region_map->editHistory.push(commit);
|
|
updateRegionMapLayoutOptions(this->currIndex);
|
|
this->region_map_layout_item->draw();
|
|
this->region_map_layout_item->select(this->currIndex);
|
|
// ^ this line necessary?
|
|
}
|
|
|
|
void RegionMapEditor::on_spinBox_tilePalette_valueChanged(int value) {
|
|
this->mapsquare_selector_item->selectPalette(value);
|
|
}
|
|
|
|
void RegionMapEditor::on_checkBox_tileHFlip_stateChanged(int state) {
|
|
this->mapsquare_selector_item->selectHFlip(state == Qt::Checked);
|
|
}
|
|
|
|
void RegionMapEditor::on_checkBox_tileVFlip_stateChanged(int state) {
|
|
this->mapsquare_selector_item->selectVFlip(state == Qt::Checked);
|
|
}
|
|
|
|
void RegionMapEditor::on_action_RegionMap_Resize_triggered() {
|
|
QDialog popup(this, Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
|
|
popup.setWindowTitle("New Tilemap Dimensions");
|
|
popup.setWindowModality(Qt::NonModal);
|
|
|
|
QFormLayout form(&popup);
|
|
|
|
// TODO: limits do not go smaller than layout
|
|
QSpinBox *widthSpinBox = new QSpinBox;
|
|
QSpinBox *heightSpinBox = new QSpinBox;
|
|
widthSpinBox->setMinimum(16);
|
|
heightSpinBox->setMinimum(16);
|
|
widthSpinBox->setMaximum(128);
|
|
heightSpinBox->setMaximum(128);
|
|
widthSpinBox->setValue(this->region_map->tilemapWidth());
|
|
heightSpinBox->setValue(this->region_map->tilemapHeight());
|
|
form.addRow(new QLabel("Width"), widthSpinBox);
|
|
form.addRow(new QLabel("Height"), heightSpinBox);
|
|
|
|
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &popup);
|
|
|
|
form.addRow(&buttonBox);
|
|
connect(&buttonBox, &QDialogButtonBox::rejected, &popup, &QDialog::reject);
|
|
connect(&buttonBox, &QDialogButtonBox::accepted, &popup, &QDialog::accept);
|
|
|
|
if (popup.exec() == QDialog::Accepted) {
|
|
resizeTilemap(widthSpinBox->value(), heightSpinBox->value());
|
|
}
|
|
return;
|
|
}
|
|
|
|
void RegionMapEditor::resizeTilemap(int width, int height) {
|
|
QByteArray oldTilemap = this->region_map->getTilemap();
|
|
int oldWidth = this->region_map->tilemapWidth();
|
|
int oldHeight = this->region_map->tilemapHeight();
|
|
this->region_map->resizeTilemap(width, height);
|
|
QByteArray newTilemap = this->region_map->getTilemap();
|
|
int newWidth = this->region_map->tilemapWidth();
|
|
int newHeight = this->region_map->tilemapHeight();
|
|
ResizeTilemap *commit = new ResizeTilemap(this->region_map, oldTilemap, newTilemap, oldWidth, oldHeight, newWidth, newHeight);
|
|
this->region_map->editHistory.push(commit);
|
|
this->currIndex = this->region_map->padLeft() * width + this->region_map->padTop();
|
|
}
|
|
|
|
void RegionMapEditor::on_action_Swap_triggered() {
|
|
QDialog popup(this, Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
|
|
popup.setWindowTitle("Swap Map Sections");
|
|
popup.setWindowModality(Qt::NonModal);
|
|
|
|
QFormLayout form(&popup);
|
|
|
|
QComboBox *oldSecBox = new QComboBox();
|
|
oldSecBox->addItems(this->project->mapSectionValueToName.values());
|
|
form.addRow(new QLabel("Map Section 1:"), oldSecBox);
|
|
QComboBox *newSecBox = new QComboBox();
|
|
newSecBox->addItems(this->project->mapSectionValueToName.values());
|
|
form.addRow(new QLabel("Map Section 2:"), newSecBox);
|
|
|
|
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &popup);
|
|
form.addRow(&buttonBox);
|
|
|
|
QString beforeSection, afterSection;
|
|
connect(&buttonBox, &QDialogButtonBox::rejected, &popup, &QDialog::reject);
|
|
connect(&buttonBox, &QDialogButtonBox::accepted, [&popup, &oldSecBox, &newSecBox, &beforeSection, &afterSection](){
|
|
beforeSection = oldSecBox->currentText();
|
|
afterSection = newSecBox->currentText();
|
|
if (!beforeSection.isEmpty() && !afterSection.isEmpty()) {
|
|
popup.accept();
|
|
}
|
|
});
|
|
|
|
if (popup.exec() == QDialog::Accepted) {
|
|
QList<LayoutSquare> oldLayout = this->region_map->getLayout(this->region_map->getLayer());
|
|
this->region_map->swapSections(beforeSection, afterSection);
|
|
QList<LayoutSquare> newLayout = this->region_map->getLayout(this->region_map->getLayer());
|
|
EditLayout *commit = new EditLayout(this->region_map, this->region_map->getLayer(), -5, oldLayout, newLayout);
|
|
commit->setText("Swap Layout Sections " + beforeSection + " <<>> " + afterSection);
|
|
this->region_map->editHistory.push(commit);
|
|
displayRegionMapLayout();
|
|
this->region_map_layout_item->select(this->region_map_layout_item->selectedTile);
|
|
}
|
|
}
|
|
|
|
void RegionMapEditor::on_action_Replace_triggered() {
|
|
QDialog popup(this, Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
|
|
popup.setWindowTitle("Replace Map Section");
|
|
popup.setWindowModality(Qt::NonModal);
|
|
|
|
QFormLayout form(&popup);
|
|
|
|
QComboBox *oldSecBox = new QComboBox();
|
|
oldSecBox->addItems(this->project->mapSectionValueToName.values());
|
|
form.addRow(new QLabel("Old Map Section:"), oldSecBox);
|
|
QComboBox *newSecBox = new QComboBox();
|
|
newSecBox->addItems(this->project->mapSectionValueToName.values());
|
|
form.addRow(new QLabel("New Map Section:"), newSecBox);
|
|
|
|
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &popup);
|
|
form.addRow(&buttonBox);
|
|
|
|
QString beforeSection, afterSection;
|
|
connect(&buttonBox, &QDialogButtonBox::rejected, &popup, &QDialog::reject);
|
|
connect(&buttonBox, &QDialogButtonBox::accepted, [&popup, &oldSecBox, &newSecBox, &beforeSection, &afterSection](){
|
|
beforeSection = oldSecBox->currentText();
|
|
afterSection = newSecBox->currentText();
|
|
if (!beforeSection.isEmpty() && !afterSection.isEmpty()) {
|
|
popup.accept();
|
|
}
|
|
});
|
|
|
|
if (popup.exec() == QDialog::Accepted) {
|
|
QList<LayoutSquare> oldLayout = this->region_map->getLayout(this->region_map->getLayer());
|
|
this->region_map->replaceSection(beforeSection, afterSection);
|
|
QList<LayoutSquare> newLayout = this->region_map->getLayout(this->region_map->getLayer());
|
|
EditLayout *commit = new EditLayout(this->region_map, this->region_map->getLayer(), -2, oldLayout, newLayout);
|
|
commit->setText("Replace Layout Section " + beforeSection + " >> " + afterSection);
|
|
this->region_map->editHistory.push(commit);
|
|
displayRegionMapLayout();
|
|
this->region_map_layout_item->select(this->region_map_layout_item->selectedTile);
|
|
}
|
|
}
|
|
|
|
void RegionMapEditor::on_action_RegionMap_ClearImage_triggered() {
|
|
QByteArray oldTilemap = this->region_map->getTilemap();
|
|
this->region_map->clearImage();
|
|
QByteArray newTilemap = this->region_map->getTilemap();
|
|
|
|
EditTilemap *commit = new EditTilemap(this->region_map, oldTilemap, newTilemap, -1);
|
|
commit->setText("Clear Tilemap");
|
|
this->region_map->editHistory.push(commit);
|
|
|
|
displayRegionMapImage();
|
|
displayRegionMapLayout();
|
|
}
|
|
|
|
void RegionMapEditor::on_action_RegionMap_ClearLayout_triggered() {
|
|
QMessageBox::StandardButton result = QMessageBox::question(
|
|
this,
|
|
"WARNING",
|
|
QString("This action will reset the entire map layout to %1, continue?").arg(this->region_map->default_map_section),
|
|
QMessageBox::Yes | QMessageBox::Cancel,
|
|
QMessageBox::Yes
|
|
);
|
|
|
|
if (result == QMessageBox::Yes) {
|
|
QList<LayoutSquare> oldLayout = this->region_map->getLayout(this->region_map->getLayer());
|
|
this->region_map->clearLayout();
|
|
QList<LayoutSquare> newLayout = this->region_map->getLayout(this->region_map->getLayer());
|
|
EditLayout *commit = new EditLayout(this->region_map, this->region_map->getLayer(), -1, oldLayout, newLayout);
|
|
commit->setText("Clear Layout");
|
|
this->region_map->editHistory.push(commit);
|
|
displayRegionMapLayout();
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
void RegionMapEditor::on_action_RegionMap_ClearEntries_triggered() {
|
|
QMessageBox::StandardButton result = QMessageBox::question(
|
|
this,
|
|
"WARNING",
|
|
"This action will remove the entire mapsection entries list, continue?",
|
|
QMessageBox::Yes | QMessageBox::Cancel,
|
|
QMessageBox::Yes
|
|
);
|
|
|
|
if (result == QMessageBox::Yes) {
|
|
ClearEntries *commit = new ClearEntries(this->region_map, this->region_map_entries);
|
|
this->region_map->editHistory.push(commit);
|
|
displayRegionMapLayout();
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool RegionMapEditor::modified() {
|
|
return !this->history.isClean() || !this->configSaved;
|
|
}
|
|
|
|
void RegionMapEditor::closeEvent(QCloseEvent *event)
|
|
{
|
|
if (this->modified()) {
|
|
QMessageBox::StandardButton result = QMessageBox::question(
|
|
this,
|
|
"porymap",
|
|
"The region map has been modified, save changes?",
|
|
QMessageBox::No | QMessageBox::Yes | QMessageBox::Cancel,
|
|
QMessageBox::Yes);
|
|
|
|
if (result == QMessageBox::Yes) {
|
|
this->on_action_RegionMap_Save_triggered();
|
|
event->accept();
|
|
} else if (result == QMessageBox::No) {
|
|
event->accept();
|
|
} else if (result == QMessageBox::Cancel) {
|
|
event->ignore();
|
|
}
|
|
} else {
|
|
event->accept();
|
|
}
|
|
|
|
porymapConfig.setRegionMapEditorGeometry(
|
|
this->saveGeometry(),
|
|
this->saveState()
|
|
);
|
|
}
|
|
|
|
void RegionMapEditor::on_verticalSlider_Zoom_Map_Image_valueChanged(int val) {
|
|
double scale = pow(scaleUpFactor, static_cast<double>(val - initialScale) / initialScale);
|
|
|
|
QTransform transform;
|
|
transform.scale(scale, scale);
|
|
int width = ceil(static_cast<double>(this->region_map->pixelWidth()) * scale);
|
|
int height = ceil(static_cast<double>(this->region_map->pixelHeight()) * scale);
|
|
|
|
ui->graphicsView_Region_Map_BkgImg->setResizeAnchor(QGraphicsView::NoAnchor);
|
|
ui->graphicsView_Region_Map_BkgImg->setTransform(transform);
|
|
ui->graphicsView_Region_Map_BkgImg->setFixedSize(width + 2, height + 2);
|
|
ui->graphicsView_Region_Map_Layout->setResizeAnchor(QGraphicsView::NoAnchor);
|
|
ui->graphicsView_Region_Map_Layout->setTransform(transform);
|
|
ui->graphicsView_Region_Map_Layout->setFixedSize(width + 2, height + 2);
|
|
ui->graphicsView_Region_Map_Entries->setResizeAnchor(QGraphicsView::NoAnchor);
|
|
ui->graphicsView_Region_Map_Entries->setTransform(transform);
|
|
ui->graphicsView_Region_Map_Entries->setFixedSize(width + 2, height + 2);
|
|
}
|
|
|
|
void RegionMapEditor::on_verticalSlider_Zoom_Image_Tiles_valueChanged(int val) {
|
|
double scale = pow(scaleUpFactor, static_cast<double>(val - initialScale) / initialScale);
|
|
|
|
QTransform transform;
|
|
transform.scale(scale, scale);
|
|
int width = ceil(static_cast<double>(this->mapsquare_selector_item->pixelWidth) * scale);
|
|
int height = ceil(static_cast<double>(this->mapsquare_selector_item->pixelHeight) * scale);
|
|
|
|
ui->graphicsView_RegionMap_Tiles->setResizeAnchor(QGraphicsView::NoAnchor);
|
|
ui->graphicsView_RegionMap_Tiles->setTransform(transform);
|
|
ui->graphicsView_RegionMap_Tiles->setFixedSize(width + 2, height + 2);
|
|
}
|