From 239f3935bfb3cd964dcd46d1f67580d86c84811d Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 14 Oct 2022 18:11:11 -0400 Subject: [PATCH 01/13] Stop treating map header bools as strings --- forms/mainwindow.ui | 4 +-- include/core/map.h | 12 ++++---- include/mainwindow.h | 2 +- src/mainwindow.cpp | 65 +++++++++++++--------------------------- src/project.cpp | 35 ++++++++++------------ src/scriptapi/apimap.cpp | 12 ++++---- src/ui/newmappopup.cpp | 12 ++++---- 7 files changed, 57 insertions(+), 85 deletions(-) diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index f7e9e245..0a71bce5 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -2013,14 +2013,14 @@ - + Allow Dig & Escape Rope - + <html><head/><body><p>Allows the player to use Dig or Escape Rope</p></body></html> diff --git a/include/core/map.h b/include/core/map.h index 717fd0f3..f87dec07 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -42,14 +42,13 @@ public: QString song; QString layoutId; QString location; - QString requiresFlash; - QString isFlyable; + bool requiresFlash; QString weather; QString type; - QString show_location; - QString allowRunning; - QString allowBiking; - QString allowEscapeRope; + bool show_location; + bool allowRunning; + bool allowBiking; + bool allowEscaping; int floorNumber = 0; QString battle_scene; QString sharedEventsMap = ""; @@ -59,6 +58,7 @@ public: bool isPersistedToFile = true; bool hasUnsavedDataChanges = false; bool needsLayoutDir = true; + bool needsHealLocation = false; QImage collision_image; QPixmap collision_pixmap; QImage image; diff --git a/include/mainwindow.h b/include/mainwindow.h index 89319d0e..16bc3cc8 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -194,7 +194,7 @@ private slots: void on_checkBox_ShowLocation_stateChanged(int selected); void on_checkBox_AllowRunning_stateChanged(int selected); void on_checkBox_AllowBiking_stateChanged(int selected); - void on_checkBox_AllowEscapeRope_stateChanged(int selected); + void on_checkBox_AllowEscaping_stateChanged(int selected); void on_spinBox_FloorNumber_valueChanged(int offset); void on_actionUse_Encounter_Json_triggered(bool checked); void on_actionMonitor_Project_Files_triggered(bool checked); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1262face..9d8d87e5 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -366,28 +366,28 @@ void MainWindow::setProjectSpecificUIVisibility() case BaseGameVersion::pokeruby: ui->checkBox_AllowRunning->setVisible(false); ui->checkBox_AllowBiking->setVisible(false); - ui->checkBox_AllowEscapeRope->setVisible(false); + ui->checkBox_AllowEscaping->setVisible(false); ui->label_AllowRunning->setVisible(false); ui->label_AllowBiking->setVisible(false); - ui->label_AllowEscapeRope->setVisible(false); + ui->label_AllowEscaping->setVisible(false); ui->actionRegion_Map_Editor->setVisible(true); break; case BaseGameVersion::pokeemerald: ui->checkBox_AllowRunning->setVisible(true); ui->checkBox_AllowBiking->setVisible(true); - ui->checkBox_AllowEscapeRope->setVisible(true); + ui->checkBox_AllowEscaping->setVisible(true); ui->label_AllowRunning->setVisible(true); ui->label_AllowBiking->setVisible(true); - ui->label_AllowEscapeRope->setVisible(true); + ui->label_AllowEscaping->setVisible(true); ui->actionRegion_Map_Editor->setVisible(true); break; case BaseGameVersion::pokefirered: ui->checkBox_AllowRunning->setVisible(true); ui->checkBox_AllowBiking->setVisible(true); - ui->checkBox_AllowEscapeRope->setVisible(true); + ui->checkBox_AllowEscaping->setVisible(true); ui->label_AllowRunning->setVisible(true); ui->label_AllowBiking->setVisible(true); - ui->label_AllowEscapeRope->setVisible(true); + ui->label_AllowEscaping->setVisible(true); // TODO: pokefirered is not set up for the Region Map Editor and vice versa. // porymap will crash on attempt. Remove below once resolved ui->actionRegion_Map_Editor->setVisible(true); @@ -763,13 +763,13 @@ void MainWindow::displayMapProperties() { const QSignalBlocker blockerA(ui->checkBox_AllowRunning); const QSignalBlocker blockerB(ui->checkBox_AllowBiking); const QSignalBlocker blockerC(ui->spinBox_FloorNumber); - const QSignalBlocker blockerD(ui->checkBox_AllowEscapeRope); + const QSignalBlocker blockerD(ui->checkBox_AllowEscaping); ui->checkBox_Visibility->setChecked(false); ui->checkBox_ShowLocation->setChecked(false); ui->checkBox_AllowRunning->setChecked(false); ui->checkBox_AllowBiking->setChecked(false); - ui->checkBox_AllowEscapeRope->setChecked(false); + ui->checkBox_AllowEscaping->setChecked(false); if (!editor || !editor->map || !editor->project) { ui->frame_3->setEnabled(false); return; @@ -787,15 +787,15 @@ void MainWindow::displayMapProperties() { ui->comboBox_Song->setCurrentText(map->song); ui->comboBox_Location->setCurrentText(map->location); - ui->checkBox_Visibility->setChecked(ParseUtil::gameStringToBool(map->requiresFlash)); + ui->checkBox_Visibility->setChecked(map->requiresFlash); ui->comboBox_Weather->setCurrentText(map->weather); ui->comboBox_Type->setCurrentText(map->type); ui->comboBox_BattleScene->setCurrentText(map->battle_scene); - ui->checkBox_ShowLocation->setChecked(ParseUtil::gameStringToBool(map->show_location)); + ui->checkBox_ShowLocation->setChecked(map->show_location); if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { - ui->checkBox_AllowRunning->setChecked(ParseUtil::gameStringToBool(map->allowRunning)); - ui->checkBox_AllowBiking->setChecked(ParseUtil::gameStringToBool(map->allowBiking)); - ui->checkBox_AllowEscapeRope->setChecked(ParseUtil::gameStringToBool(map->allowEscapeRope)); + ui->checkBox_AllowRunning->setChecked(map->allowRunning); + ui->checkBox_AllowBiking->setChecked(map->allowBiking); + ui->checkBox_AllowEscaping->setChecked(map->allowEscaping); } ui->spinBox_FloorNumber->setValue(map->floorNumber); @@ -854,12 +854,7 @@ void MainWindow::on_comboBox_BattleScene_currentTextChanged(const QString &battl void MainWindow::on_checkBox_Visibility_stateChanged(int selected) { if (editor && editor->map) { - bool checked = selected == Qt::Checked; - if (checked) { - editor->map->requiresFlash = "TRUE"; - } else { - editor->map->requiresFlash = "FALSE"; - } + editor->map->requiresFlash = (selected == Qt::Checked); markMapEdited(); } } @@ -867,12 +862,7 @@ void MainWindow::on_checkBox_Visibility_stateChanged(int selected) void MainWindow::on_checkBox_ShowLocation_stateChanged(int selected) { if (editor && editor->map) { - bool checked = selected == Qt::Checked; - if (checked) { - editor->map->show_location = "TRUE"; - } else { - editor->map->show_location = "FALSE"; - } + editor->map->show_location = (selected == Qt::Checked); markMapEdited(); } } @@ -880,12 +870,7 @@ void MainWindow::on_checkBox_ShowLocation_stateChanged(int selected) void MainWindow::on_checkBox_AllowRunning_stateChanged(int selected) { if (editor && editor->map) { - bool checked = selected == Qt::Checked; - if (checked) { - editor->map->allowRunning = "1"; - } else { - editor->map->allowRunning = "0"; - } + editor->map->allowRunning = (selected == Qt::Checked); markMapEdited(); } } @@ -893,25 +878,15 @@ void MainWindow::on_checkBox_AllowRunning_stateChanged(int selected) void MainWindow::on_checkBox_AllowBiking_stateChanged(int selected) { if (editor && editor->map) { - bool checked = selected == Qt::Checked; - if (checked) { - editor->map->allowBiking = "1"; - } else { - editor->map->allowBiking = "0"; - } + editor->map->allowBiking = (selected == Qt::Checked); markMapEdited(); } } -void MainWindow::on_checkBox_AllowEscapeRope_stateChanged(int selected) +void MainWindow::on_checkBox_AllowEscaping_stateChanged(int selected) { if (editor && editor->map) { - bool checked = selected == Qt::Checked; - if (checked) { - editor->map->allowEscapeRope = "1"; - } else { - editor->map->allowEscapeRope = "0"; - } + editor->map->allowEscaping = (selected == Qt::Checked); markMapEdited(); } } @@ -1196,7 +1171,7 @@ void MainWindow::onNewMapCreated() { sortMapList(); setMap(newMapName, true); - if (ParseUtil::gameStringToBool(newMap->isFlyable)) { + if (newMap->needsHealLocation) { addNewEvent(EventType::HealLocation); editor->project->saveHealLocationStruct(newMap); editor->save();// required diff --git a/src/project.cpp b/src/project.cpp index 55243012..0a3007ec 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -193,16 +193,15 @@ bool Project::loadMapData(Map* map) { map->song = mapObj["music"].toString(); map->layoutId = mapObj["layout"].toString(); map->location = mapObj["region_map_section"].toString(); - map->requiresFlash = QString::number(mapObj["requires_flash"].toBool()); + map->requiresFlash = mapObj["requires_flash"].toBool(); map->weather = mapObj["weather"].toString(); map->type = mapObj["map_type"].toString(); - map->requiresFlash = QString::number(mapObj["requires_flash"].toBool()); - map->show_location = QString::number(mapObj["show_map_name"].toBool()); + map->show_location = mapObj["show_map_name"].toBool(); map->battle_scene = mapObj["battle_scene"].toString(); if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { - map->allowBiking = QString::number(mapObj["allow_cycling"].toBool()); - map->allowEscapeRope = QString::number(mapObj["allow_escaping"].toBool()); - map->allowRunning = QString::number(mapObj["allow_running"].toBool()); + map->allowBiking = mapObj["allow_cycling"].toBool(); + map->allowEscaping = mapObj["allow_escaping"].toBool(); + map->allowRunning = mapObj["allow_running"].toBool(); } if (projectConfig.getFloorNumberEnabled()) { map->floorNumber = mapObj["floor_number"].toInt(); @@ -453,17 +452,15 @@ QString Project::readMapLocation(QString map_name) { void Project::setNewMapHeader(Map* map, int mapIndex) { map->layoutId = QString("%1").arg(mapIndex); map->location = mapSectionValueToName.value(0); - map->requiresFlash = "FALSE"; + map->requiresFlash = false; map->weather = weatherNames.value(0, "WEATHER_NONE"); map->type = mapTypes.value(0, "MAP_TYPE_NONE"); map->song = defaultSong; - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) { - map->show_location = "TRUE"; - } else { - map->allowBiking = "1"; - map->allowEscapeRope = "0"; - map->allowRunning = "1"; - map->show_location = "1"; + map->show_location = true; + if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { + map->allowBiking = true; + map->allowEscaping = false; + map->allowRunning = true; } if (projectConfig.getFloorNumberEnabled()) { map->floorNumber = 0; @@ -1341,15 +1338,15 @@ void Project::saveMap(Map *map) { mapObj["layout"] = map->layout->id; mapObj["music"] = map->song; mapObj["region_map_section"] = map->location; - mapObj["requires_flash"] = ParseUtil::gameStringToBool(map->requiresFlash); + mapObj["requires_flash"] = map->requiresFlash; mapObj["weather"] = map->weather; mapObj["map_type"] = map->type; if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { - mapObj["allow_cycling"] = ParseUtil::gameStringToBool(map->allowBiking); - mapObj["allow_escaping"] = ParseUtil::gameStringToBool(map->allowEscapeRope); - mapObj["allow_running"] = ParseUtil::gameStringToBool(map->allowRunning); + mapObj["allow_cycling"] = map->allowBiking; + mapObj["allow_escaping"] = map->allowEscaping; + mapObj["allow_running"] = map->allowRunning; } - mapObj["show_map_name"] = ParseUtil::gameStringToBool(map->show_location); + mapObj["show_map_name"] = map->show_location; if (projectConfig.getFloorNumberEnabled()) { mapObj["floor_number"] = map->floorNumber; } diff --git a/src/scriptapi/apimap.cpp b/src/scriptapi/apimap.cpp index 419ef1c6..2a2cbb28 100644 --- a/src/scriptapi/apimap.cpp +++ b/src/scriptapi/apimap.cpp @@ -815,7 +815,7 @@ void MainWindow::setLocation(QString location) { bool MainWindow::getRequiresFlash() { if (!this->editor || !this->editor->map) return false; - return ParseUtil::gameStringToBool(this->editor->map->requiresFlash); + return this->editor->map->requiresFlash; } void MainWindow::setRequiresFlash(bool require) { @@ -875,7 +875,7 @@ void MainWindow::setBattleScene(QString battleScene) { bool MainWindow::getShowLocationName() { if (!this->editor || !this->editor->map) return false; - return ParseUtil::gameStringToBool(this->editor->map->show_location); + return this->editor->map->show_location; } void MainWindow::setShowLocationName(bool show) { @@ -887,7 +887,7 @@ void MainWindow::setShowLocationName(bool show) { bool MainWindow::getAllowRunning() { if (!this->editor || !this->editor->map) return false; - return ParseUtil::gameStringToBool(this->editor->map->allowRunning); + return this->editor->map->allowRunning; } void MainWindow::setAllowRunning(bool allow) { @@ -899,7 +899,7 @@ void MainWindow::setAllowRunning(bool allow) { bool MainWindow::getAllowBiking() { if (!this->editor || !this->editor->map) return false; - return ParseUtil::gameStringToBool(this->editor->map->allowBiking); + return this->editor->map->allowBiking; } void MainWindow::setAllowBiking(bool allow) { @@ -911,13 +911,13 @@ void MainWindow::setAllowBiking(bool allow) { bool MainWindow::getAllowEscaping() { if (!this->editor || !this->editor->map) return false; - return ParseUtil::gameStringToBool(this->editor->map->allowEscapeRope); + return this->editor->map->allowEscaping; } void MainWindow::setAllowEscaping(bool allow) { if (!this->ui) return; - this->ui->checkBox_AllowEscapeRope->setChecked(allow); + this->ui->checkBox_AllowEscaping->setChecked(allow); } int MainWindow::getFloorNumber() { diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index a25e5613..8cd41b5a 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -266,9 +266,9 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { newMap->type = this->ui->comboBox_NewMap_Type->currentText(); newMap->location = this->ui->comboBox_NewMap_Location->currentText(); newMap->song = this->ui->comboBox_Song->currentText(); - newMap->requiresFlash = "0"; + newMap->requiresFlash = false; newMap->weather = this->project->weatherNames.value(0, "WEATHER_NONE"); - newMap->show_location = this->ui->checkBox_NewMap_Show_Location->isChecked() ? "1" : "0"; + newMap->show_location = this->ui->checkBox_NewMap_Show_Location->isChecked(); newMap->battle_scene = this->project->mapBattleScenes.value(0, "MAP_BATTLE_SCENE_NORMAL"); if (this->existingLayout) { @@ -301,13 +301,13 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { } if (this->ui->checkBox_NewMap_Flyable->isChecked()) { - newMap->isFlyable = "TRUE"; + newMap->needsHealLocation = true; } if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { - newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked() ? "1" : "0"; - newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked() ? "1" : "0"; - newMap->allowEscapeRope = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked() ? "1" : "0"; + newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked(); + newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked(); + newMap->allowEscaping = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked(); } if (projectConfig.getFloorNumberEnabled()) { newMap->floorNumber = this->ui->spinBox_NewMap_Floor_Number->value(); From 6ffcb58e5ed87b0e32a6b8bc259b18b101ad0aa4 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 14 Oct 2022 18:55:18 -0400 Subject: [PATCH 02/13] Convert JSON values by type, except events --- include/core/parseutil.h | 4 ++ include/project.h | 2 +- src/core/parseutil.cpp | 54 +++++++++++++++-- src/mainwindow.cpp | 4 +- src/project.cpp | 118 +++++++++++++++++++------------------ src/ui/prefab.cpp | 22 +++---- src/ui/regionmapeditor.cpp | 12 ++-- 7 files changed, 134 insertions(+), 82 deletions(-) diff --git a/include/core/parseutil.h b/include/core/parseutil.h index 5cb07366..0200d7ae 100644 --- a/include/core/parseutil.h +++ b/include/core/parseutil.h @@ -71,7 +71,11 @@ public: static QString removeLineComments(QString text, const QStringList &commentSymbols); static QStringList splitShellCommand(QStringView command); + static int gameStringToInt(QString gameString, bool * ok = nullptr); static bool gameStringToBool(QString gameString, bool * ok = nullptr); + static QString jsonToQString(QJsonValue value, bool * ok = nullptr); + static int jsonToInt(QJsonValue value, bool * ok = nullptr); + static bool jsonToBool(QJsonValue value, bool * ok = nullptr); private: QString root; diff --git a/include/project.h b/include/project.h index 0828284f..cdc81615 100644 --- a/include/project.h +++ b/include/project.h @@ -134,7 +134,7 @@ public: bool readSpeciesIconPaths(); QMap speciesToIconPath; - QMap getTopLevelMapFields(); + QSet getTopLevelMapFields(); bool loadMapData(Map*); bool readMapLayouts(); bool loadLayout(MapLayout *); diff --git a/src/core/parseutil.cpp b/src/core/parseutil.cpp index 63fbd84d..f765ff79 100644 --- a/src/core/parseutil.cpp +++ b/src/core/parseutil.cpp @@ -402,13 +402,17 @@ QMap ParseUtil::readNamedIndexCArray(const QString &filename, return map; } -bool ParseUtil::gameStringToBool(QString gameString, bool * ok) { +int ParseUtil::gameStringToInt(QString gameString, bool * ok) { if (ok) *ok = true; if (QString::compare(gameString, "TRUE", Qt::CaseInsensitive) == 0) - return true; + return 1; if (QString::compare(gameString, "FALSE", Qt::CaseInsensitive) == 0) - return false; - return gameString.toInt(ok) != 0; + return 0; + return gameString.toInt(ok); +} + +bool ParseUtil::gameStringToBool(QString gameString, bool * ok) { + return gameStringToInt(gameString, ok) != 0; } QMap> ParseUtil::readCStructs(const QString &filename, const QString &label, const QHash memberMap) { @@ -520,6 +524,48 @@ bool ParseUtil::ensureFieldsExist(const QJsonObject &obj, const QList & return true; } +// QJsonValues are strictly typed, and so will not attempt any implicit conversions. +// The below functions are for attempting to convert a JSON value read from the user's +// project to a QString, int, or bool (whichever Porymap expects). +QString ParseUtil::jsonToQString(QJsonValue value, bool * ok) { + if (ok) *ok = true; + switch (value.type()) + { + case QJsonValue::String: return value.toString(); + case QJsonValue::Double: return QString::number(value.toInt()); + case QJsonValue::Bool: return QString::number(value.toBool()); + default: break; + } + if (ok) *ok = false; + return QString(); +} + +int ParseUtil::jsonToInt(QJsonValue value, bool * ok) { + if (ok) *ok = true; + switch (value.type()) + { + case QJsonValue::String: return ParseUtil::gameStringToInt(value.toString(), ok); + case QJsonValue::Double: return value.toInt(); + case QJsonValue::Bool: return value.toBool(); + default: break; + } + if (ok) *ok = false; + return 0; +} + +bool ParseUtil::jsonToBool(QJsonValue value, bool * ok) { + if (ok) *ok = true; + switch (value.type()) + { + case QJsonValue::String: return ParseUtil::gameStringToBool(value.toString(), ok); + case QJsonValue::Double: return value.toInt() != 0; + case QJsonValue::Bool: return value.toBool(); + default: break; + } + if (ok) *ok = false; + return false; +} + int ParseUtil::getScriptLineNumber(const QString &filePath, const QString &scriptLabel) { if (scriptLabel.isEmpty()) return 0; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9d8d87e5..41d0a7a2 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1574,8 +1574,8 @@ void MainWindow::paste() { } QJsonArray metatilesArray = pasteObject["metatile_selection"].toArray(); QJsonArray collisionsArray = pasteObject["collision_selection"].toArray(); - int width = pasteObject["width"].toInt(); - int height = pasteObject["height"].toInt(); + int width = ParseUtil::jsonToInt(pasteObject["width"]); + int height = ParseUtil::jsonToInt(pasteObject["height"]); QList metatiles; QList> collisions; for (auto tile : metatilesArray) { diff --git a/src/project.cpp b/src/project.cpp index 0a3007ec..7632191e 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -142,36 +142,37 @@ void Project::setNewMapConnections(Map *map) { map->connections.clear(); } -static QMap defaultTopLevelMapFields { - {"id", true}, - {"name", true}, - {"layout", true}, - {"music", true}, - {"region_map_section", true}, - {"requires_flash", true}, - {"weather", true}, - {"map_type", true}, - {"show_map_name", true}, - {"battle_scene", true}, - {"connections", true}, - {"object_events", true}, - {"warp_events", true}, - {"coord_events", true}, - {"bg_events", true}, - {"shared_events_map", true}, - {"shared_scripts_map", true}, +const QSet defaultTopLevelMapFields = { + "id", + "name", + "layout", + "music", + "region_map_section", + "requires_flash", + "weather", + "map_type", + "show_map_name", + "battle_scene", + "connections", + "object_events", + "warp_events", + "coord_events", + "bg_events", + "shared_events_map", + "shared_scripts_map", + "test", }; -QMap Project::getTopLevelMapFields() { - QMap topLevelMapFields = defaultTopLevelMapFields; +QSet Project::getTopLevelMapFields() { + QSet topLevelMapFields = defaultTopLevelMapFields; if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { - topLevelMapFields.insert("allow_cycling", true); - topLevelMapFields.insert("allow_escaping", true); - topLevelMapFields.insert("allow_running", true); + topLevelMapFields.insert("allow_cycling"); + topLevelMapFields.insert("allow_escaping"); + topLevelMapFields.insert("allow_running"); } if (projectConfig.getFloorNumberEnabled()) { - topLevelMapFields.insert("floor_number", true); + topLevelMapFields.insert("floor_number"); } return topLevelMapFields; } @@ -190,24 +191,25 @@ bool Project::loadMapData(Map* map) { QJsonObject mapObj = mapDoc.object(); - map->song = mapObj["music"].toString(); - map->layoutId = mapObj["layout"].toString(); - map->location = mapObj["region_map_section"].toString(); - map->requiresFlash = mapObj["requires_flash"].toBool(); - map->weather = mapObj["weather"].toString(); - map->type = mapObj["map_type"].toString(); - map->show_location = mapObj["show_map_name"].toBool(); - map->battle_scene = mapObj["battle_scene"].toString(); + map->song = ParseUtil::jsonToQString(mapObj["music"]); + map->layoutId = ParseUtil::jsonToQString(mapObj["layout"]); + map->location = ParseUtil::jsonToQString(mapObj["region_map_section"]); + map->requiresFlash = ParseUtil::jsonToBool(mapObj["requires_flash"]); + map->weather = ParseUtil::jsonToQString(mapObj["weather"]); + map->type = ParseUtil::jsonToQString(mapObj["map_type"]); + map->show_location = ParseUtil::jsonToBool(mapObj["show_map_name"]); + map->battle_scene = ParseUtil::jsonToQString(mapObj["battle_scene"]); + if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { - map->allowBiking = mapObj["allow_cycling"].toBool(); - map->allowEscaping = mapObj["allow_escaping"].toBool(); - map->allowRunning = mapObj["allow_running"].toBool(); + map->allowBiking = ParseUtil::jsonToBool(mapObj["allow_cycling"]); + map->allowEscaping = ParseUtil::jsonToBool(mapObj["allow_escaping"]); + map->allowRunning = ParseUtil::jsonToBool(mapObj["allow_running"]); } if (projectConfig.getFloorNumberEnabled()) { - map->floorNumber = mapObj["floor_number"].toInt(); + map->floorNumber = ParseUtil::jsonToInt(mapObj["floor_number"]); } - map->sharedEventsMap = mapObj["shared_events_map"].toString(); - map->sharedScriptsMap = mapObj["shared_scripts_map"].toString(); + map->sharedEventsMap = ParseUtil::jsonToQString(mapObj["shared_events_map"]); + map->sharedScriptsMap = ParseUtil::jsonToQString(mapObj["shared_scripts_map"]); // Events map->events[EventGroup::Object].clear(); @@ -394,9 +396,9 @@ bool Project::loadMapData(Map* map) { for (int i = 0; i < connectionsArr.size(); i++) { QJsonObject connectionObj = connectionsArr[i].toObject(); MapConnection *connection = new MapConnection; - connection->direction = connectionObj["direction"].toString(); - connection->offset = QString::number(connectionObj["offset"].toInt()); - QString mapConstant = connectionObj["map"].toString(); + connection->direction = ParseUtil::jsonToQString(connectionObj["direction"]); + connection->offset = ParseUtil::jsonToInt(connectionObj["offset"]); + QString mapConstant = ParseUtil::jsonToQString(connectionObj["map"]); if (mapConstantsToMapNames.contains(mapConstant)) { connection->map_name = mapConstantsToMapNames.value(mapConstant); map->connections.append(connection); @@ -407,10 +409,10 @@ bool Project::loadMapData(Map* map) { } // Check for custom fields - QMap baseFields = this->getTopLevelMapFields(); + QSet baseFields = this->getTopLevelMapFields(); for (QString key : mapObj.keys()) { if (!baseFields.contains(key)) { - map->customHeaders.insert(key, mapObj[key].toString()); + map->customHeaders.insert(key, ParseUtil::jsonToQString(mapObj[key])); } } @@ -430,7 +432,7 @@ QString Project::readMapLayoutId(QString map_name) { } QJsonObject mapObj = mapDoc.object(); - return mapObj["layout"].toString(); + return ParseUtil::jsonToQString(mapObj["layout"]); } QString Project::readMapLocation(QString map_name) { @@ -446,7 +448,7 @@ QString Project::readMapLocation(QString map_name) { } QJsonObject mapObj = mapDoc.object(); - return mapObj["region_map_section"].toString(); + return ParseUtil::jsonToQString(mapObj["region_map_section"]); } void Project::setNewMapHeader(Map* map, int mapIndex) { @@ -518,7 +520,7 @@ bool Project::readMapLayouts() { return false; } - layoutsLabel = layoutsObj["layouts_table_label"].toString(); + layoutsLabel = ParseUtil::jsonToQString(layoutsObj["layouts_table_label"]); if (layoutsLabel.isNull()) { layoutsLabel = "gMapLayouts"; logWarn(QString("'layouts_table_label' value is missing from %1. Defaulting to %2") @@ -550,36 +552,36 @@ bool Project::readMapLayouts() { return false; } MapLayout *layout = new MapLayout(); - layout->id = layoutObj["id"].toString(); + layout->id = ParseUtil::jsonToQString(layoutObj["id"]); if (layout->id.isEmpty()) { logError(QString("Missing 'id' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); return false; } - layout->name = layoutObj["name"].toString(); + layout->name = ParseUtil::jsonToQString(layoutObj["name"]); if (layout->name.isEmpty()) { logError(QString("Missing 'name' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); return false; } - int lwidth = layoutObj["width"].toInt(); + int lwidth = ParseUtil::jsonToInt(layoutObj["width"]); if (lwidth <= 0) { logError(QString("Invalid layout 'width' value '%1' on layout %2 in %3. Must be greater than 0.").arg(lwidth).arg(i).arg(layoutsFilepath)); return false; } layout->width = QString::number(lwidth); - int lheight = layoutObj["height"].toInt(); + int lheight = ParseUtil::jsonToInt(layoutObj["height"]); if (lheight <= 0) { logError(QString("Invalid layout 'height' value '%1' on layout %2 in %3. Must be greater than 0.").arg(lheight).arg(i).arg(layoutsFilepath)); return false; } layout->height = QString::number(lheight); if (useCustomBorderSize) { - int bwidth = layoutObj["border_width"].toInt(); + int bwidth = ParseUtil::jsonToInt(layoutObj["border_width"]); if (bwidth <= 0) { // 0 is an expected border width/height that should be handled, GF used it for the RS layouts in FRLG logWarn(QString("Invalid layout 'border_width' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bwidth).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_WIDTH)); bwidth = DEFAULT_BORDER_WIDTH; } layout->border_width = QString::number(bwidth); - int bheight = layoutObj["border_height"].toInt(); + int bheight = ParseUtil::jsonToInt(layoutObj["border_height"]); if (bheight <= 0) { logWarn(QString("Invalid layout 'border_height' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bheight).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_HEIGHT)); bheight = DEFAULT_BORDER_HEIGHT; @@ -589,22 +591,22 @@ bool Project::readMapLayouts() { layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); } - layout->tileset_primary_label = layoutObj["primary_tileset"].toString(); + layout->tileset_primary_label = ParseUtil::jsonToQString(layoutObj["primary_tileset"]); if (layout->tileset_primary_label.isEmpty()) { logError(QString("Missing 'primary_tileset' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); return false; } - layout->tileset_secondary_label = layoutObj["secondary_tileset"].toString(); + layout->tileset_secondary_label = ParseUtil::jsonToQString(layoutObj["secondary_tileset"]); if (layout->tileset_secondary_label.isEmpty()) { logError(QString("Missing 'secondary_tileset' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); return false; } - layout->border_path = layoutObj["border_filepath"].toString(); + layout->border_path = ParseUtil::jsonToQString(layoutObj["border_filepath"]); if (layout->border_path.isEmpty()) { logError(QString("Missing 'border_filepath' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); return false; } - layout->blockdata_path = layoutObj["blockdata_filepath"].toString(); + layout->blockdata_path = ParseUtil::jsonToQString(layoutObj["blockdata_filepath"]); if (layout->blockdata_path.isEmpty()) { logError(QString("Missing 'blockdata_filepath' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); return false; @@ -1840,12 +1842,12 @@ bool Project::readMapGroups() { QStringList maps; QStringList groups; for (int groupIndex = 0; groupIndex < mapGroupOrder.size(); groupIndex++) { - QString groupName = mapGroupOrder.at(groupIndex).toString(); + QString groupName = ParseUtil::jsonToQString(mapGroupOrder.at(groupIndex)); QJsonArray mapNames = mapGroupsObj.value(groupName).toArray(); groupedMaps.append(QStringList()); groups.append(groupName); for (int j = 0; j < mapNames.size(); j++) { - QString mapName = mapNames.at(j).toString(); + QString mapName = ParseUtil::jsonToQString(mapNames.at(j)); mapGroups.insert(mapName, groupIndex); groupedMaps[groupIndex].append(mapName); maps.append(mapName); diff --git a/src/ui/prefab.cpp b/src/ui/prefab.cpp index e9e3b3b0..87bae518 100644 --- a/src/ui/prefab.cpp +++ b/src/ui/prefab.cpp @@ -46,14 +46,14 @@ void Prefab::loadPrefabs() { if (prefabObj.isEmpty()) continue; - int width = prefabObj["width"].toInt(); - int height = prefabObj["height"].toInt(); + int width = ParseUtil::jsonToInt(prefabObj["width"]); + int height = ParseUtil::jsonToInt(prefabObj["height"]); if (width <= 0 || height <= 0) continue; - QString name = prefabObj["name"].toString(); - QString primaryTileset = prefabObj["primary_tileset"].toString(); - QString secondaryTileset = prefabObj["secondary_tileset"].toString(); + QString name = ParseUtil::jsonToQString(prefabObj["name"]); + QString primaryTileset = ParseUtil::jsonToQString(prefabObj["primary_tileset"]); + QString secondaryTileset = ParseUtil::jsonToQString(prefabObj["secondary_tileset"]); MetatileSelection selection; selection.dimensions = QPoint(width, height); @@ -65,17 +65,17 @@ void Prefab::loadPrefabs() { QJsonArray metatiles = prefabObj["metatiles"].toArray(); for (int j = 0; j < metatiles.size(); j++) { QJsonObject metatileObj = metatiles[j].toObject(); - int x = metatileObj["x"].toInt(); - int y = metatileObj["y"].toInt(); + int x = ParseUtil::jsonToInt(metatileObj["x"]); + int y = ParseUtil::jsonToInt(metatileObj["y"]); if (x < 0 || x >= width || y < 0 || y >= height) continue; int index = y * width + x; - int metatileId = metatileObj["metatile_id"].toInt(); + int metatileId = ParseUtil::jsonToInt(metatileObj["metatile_id"]); if (metatileId < 0 || metatileId >= Project::getNumMetatilesTotal()) continue; - selection.metatileItems[index].metatileId = metatileObj["metatile_id"].toInt(); - selection.collisionItems[index].collision = metatileObj["collision"].toInt(); - selection.collisionItems[index].elevation = metatileObj["elevation"].toInt(); + selection.metatileItems[index].metatileId = ParseUtil::jsonToInt(metatileObj["metatile_id"]); + selection.collisionItems[index].collision = ParseUtil::jsonToInt(metatileObj["collision"]); + selection.collisionItems[index].elevation = ParseUtil::jsonToInt(metatileObj["elevation"]); selection.metatileItems[index].enabled = true; selection.collisionItems[index].enabled = true; } diff --git a/src/ui/regionmapeditor.cpp b/src/ui/regionmapeditor.cpp index dc2c458e..8257231c 100644 --- a/src/ui/regionmapeditor.cpp +++ b/src/ui/regionmapeditor.cpp @@ -125,13 +125,13 @@ bool RegionMapEditor::loadRegionMapEntries() { for (auto entryRef : object["map_sections"].toArray()) { QJsonObject entryObject = entryRef.toObject(); - QString entryMapSection = entryObject["map_section"].toString(); + QString entryMapSection = ParseUtil::jsonToQString(entryObject["map_section"]); MapSectionEntry entry; - entry.name = entryObject["name"].toString(); - entry.x = entryObject["x"].toInt(); - entry.y = entryObject["y"].toInt(); - entry.width = entryObject["width"].toInt(); - entry.height = entryObject["height"].toInt(); + 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; } From ec626a59a71a27fadaf8dc6cb8a4f61b075c65dc Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Oct 2022 03:22:51 -0400 Subject: [PATCH 03/13] Display custom header values according to type --- include/core/map.h | 2 +- src/editor.cpp | 2 +- src/mainwindow.cpp | 20 +++++++++++++++++++- src/project.cpp | 4 ++-- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/include/core/map.h b/include/core/map.h index f87dec07..fb898317 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -53,7 +53,7 @@ public: QString battle_scene; QString sharedEventsMap = ""; QString sharedScriptsMap = ""; - QMap customHeaders; + QMap customHeaders; MapLayout *layout; bool isPersistedToFile = true; bool hasUnsavedDataChanges = false; diff --git a/src/editor.cpp b/src/editor.cpp index 61cf2fad..290a30b6 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1958,7 +1958,7 @@ void Editor::updateCustomMapHeaderValues(QTableWidget *table) if (value) valueStr = value->text(); fields[keyStr] = valueStr; } - map->customHeaders = fields; + //map->customHeaders = fields; emit editedMapData(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 41d0a7a2..cba737f0 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -803,11 +803,29 @@ void MainWindow::displayMapProperties() { ui->tableWidget_CustomHeaderFields->blockSignals(true); ui->tableWidget_CustomHeaderFields->setRowCount(0); for (auto it = map->customHeaders.begin(); it != map->customHeaders.end(); it++) { + QTableWidgetItem * tableItem; + QJsonValue value = it.value(); + switch (value.type()) + { + case QJsonValue::String: + case QJsonValue::Double: + tableItem = new QTableWidgetItem(ParseUtil::jsonToQString(value)); + break; + case QJsonValue::Bool: + tableItem = new QTableWidgetItem(""); + tableItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked); + break; + default: + tableItem = new QTableWidgetItem("This value cannot be edited from this table"); + tableItem->setFlags(Qt::NoItemFlags); + break; + } int rowIndex = ui->tableWidget_CustomHeaderFields->rowCount(); ui->tableWidget_CustomHeaderFields->insertRow(rowIndex); ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 0, new QTableWidgetItem(it.key())); - ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 1, new QTableWidgetItem(it.value())); + ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 1, tableItem); } + ui->tableWidget_CustomHeaderFields->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); ui->tableWidget_CustomHeaderFields->blockSignals(false); } diff --git a/src/project.cpp b/src/project.cpp index 7632191e..7b41350e 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -412,7 +412,7 @@ bool Project::loadMapData(Map* map) { QSet baseFields = this->getTopLevelMapFields(); for (QString key : mapObj.keys()) { if (!baseFields.contains(key)) { - map->customHeaders.insert(key, ParseUtil::jsonToQString(mapObj[key])); + map->customHeaders.insert(key, mapObj[key]); } } @@ -1440,7 +1440,7 @@ void Project::saveMap(Map *map) { // Custom header fields. for (QString key : map->customHeaders.keys()) { - mapObj[key] = map->customHeaders[key]; + //mapObj[key] = map->customHeaders[key]; } OrderedJson mapJson(mapObj); From 463a7e01f6736bcc8dbc8381e67dbdf8128f9f40 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Oct 2022 14:49:35 -0400 Subject: [PATCH 04/13] Save custom header values by type --- include/mainwindow.h | 1 + src/editor.cpp | 36 +++++++++++++++++++++++++++--------- src/mainwindow.cpp | 43 +++++++++++++++++++++++++------------------ src/project.cpp | 23 ++++++++++++++++++++++- 4 files changed, 75 insertions(+), 28 deletions(-) diff --git a/include/mainwindow.h b/include/mainwindow.h index 16bc3cc8..4eae446f 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -388,6 +388,7 @@ private: void redrawMetatileSelection(); QObjectList shortcutableObjects() const; + QTableWidgetItem * createNewCustomHeaderItem(QJsonValue value); }; enum MapListUserRoles { diff --git a/src/editor.cpp b/src/editor.cpp index 290a30b6..50da1ca2 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1948,17 +1948,35 @@ void Editor::toggleBorderVisibility(bool visible, bool enableScriptCallback) void Editor::updateCustomMapHeaderValues(QTableWidget *table) { - QMap fields; + QMap fields; for (int row = 0; row < table->rowCount(); row++) { - QString keyStr = ""; - QString valueStr = ""; - QTableWidgetItem *key = table->item(row, 0); - QTableWidgetItem *value = table->item(row, 1); - if (key) keyStr = key->text(); - if (value) valueStr = value->text(); - fields[keyStr] = valueStr; + QString key = ""; + QString value = ""; + QTableWidgetItem *keyItem = table->item(row, 0); + QTableWidgetItem *valueItem = table->item(row, 1); + if (keyItem) key = keyItem->text(); + if (!key.isEmpty() && valueItem) { + // Use the original table value to determine which type the input text should be saved as. + QJsonValue value = valueItem->data(Qt::UserRole).toJsonValue(); + switch (value.type()) + { + case QJsonValue::String: + value = QJsonValue(valueItem->text()); + break; + case QJsonValue::Double: + value = QJsonValue(valueItem->text().toInt()); + break; + case QJsonValue::Bool: + value = QJsonValue(valueItem->checkState() == Qt::Checked); + break; + default: + // Arrays and objects can't be updated via the table, just preserve the original value. + break; + } + fields[key] = value; + } } - //map->customHeaders = fields; + map->customHeaders = fields; emit editedMapData(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index cba737f0..94055e76 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -803,27 +803,10 @@ void MainWindow::displayMapProperties() { ui->tableWidget_CustomHeaderFields->blockSignals(true); ui->tableWidget_CustomHeaderFields->setRowCount(0); for (auto it = map->customHeaders.begin(); it != map->customHeaders.end(); it++) { - QTableWidgetItem * tableItem; - QJsonValue value = it.value(); - switch (value.type()) - { - case QJsonValue::String: - case QJsonValue::Double: - tableItem = new QTableWidgetItem(ParseUtil::jsonToQString(value)); - break; - case QJsonValue::Bool: - tableItem = new QTableWidgetItem(""); - tableItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked); - break; - default: - tableItem = new QTableWidgetItem("This value cannot be edited from this table"); - tableItem->setFlags(Qt::NoItemFlags); - break; - } int rowIndex = ui->tableWidget_CustomHeaderFields->rowCount(); ui->tableWidget_CustomHeaderFields->insertRow(rowIndex); ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 0, new QTableWidgetItem(it.key())); - ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 1, tableItem); + ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 1, createNewCustomHeaderItem(it.value())); } ui->tableWidget_CustomHeaderFields->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); ui->tableWidget_CustomHeaderFields->blockSignals(false); @@ -3097,11 +3080,35 @@ void MainWindow::togglePreferenceSpecificUi() { ui->actionOpen_Project_in_Text_Editor->setEnabled(true); } +QTableWidgetItem * MainWindow::createNewCustomHeaderItem(QJsonValue value) { + QTableWidgetItem * tableItem; + switch (value.type()) + { + case QJsonValue::String: + case QJsonValue::Double: + tableItem = new QTableWidgetItem(ParseUtil::jsonToQString(value)); + break; + case QJsonValue::Bool: + tableItem = new QTableWidgetItem(""); + tableItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked); + break; + default: + tableItem = new QTableWidgetItem("This value cannot be edited from this table"); + tableItem->setFlags(Qt::NoItemFlags); + break; + } + tableItem->setData(Qt::UserRole, value); // Save the original value/type for when it's written back to the project + return tableItem; +} + void MainWindow::on_pushButton_AddCustomHeaderField_clicked() { int rowIndex = this->ui->tableWidget_CustomHeaderFields->rowCount(); this->ui->tableWidget_CustomHeaderFields->insertRow(rowIndex); this->ui->tableWidget_CustomHeaderFields->selectRow(rowIndex); + // TODO: New items default to string, allow type selection + QJsonValue defaultValue = QJsonValue(QString("")); + this->ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 1, createNewCustomHeaderItem(defaultValue)); this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields); } diff --git a/src/project.cpp b/src/project.cpp index 7b41350e..6207fe5b 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1440,7 +1440,28 @@ void Project::saveMap(Map *map) { // Custom header fields. for (QString key : map->customHeaders.keys()) { - //mapObj[key] = map->customHeaders[key]; + QJsonValue value = map->customHeaders[key]; + switch (value.type()) + { + default: + case QJsonValue::String: + mapObj[key] = value.toString(); + break; + case QJsonValue::Double: + mapObj[key] = value.toInt(); + break; + case QJsonValue::Bool: + mapObj[key] = value.toBool(); + break; + case QJsonValue::Array: + // TODO: Custom array values are replaced with empty strings + mapObj[key] = value.toString(); + break; + case QJsonValue::Object: + // TODO: Custom object values are replaced with empty strings + mapObj[key] = value.toString(); + break; + } } OrderedJson mapJson(mapObj); From 6b55dc935d0c821317ff002e3fac94598a9504c2 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Oct 2022 22:32:05 -0400 Subject: [PATCH 05/13] Add custom header value type selection --- forms/mainwindow.ui | 5 ++++ include/mainwindow.h | 2 +- src/editor.cpp | 48 ++++++++++++++++-------------- src/mainwindow.cpp | 71 ++++++++++++++++++++++++++++++-------------- 4 files changed, 80 insertions(+), 46 deletions(-) diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index 0a71bce5..1a2268a2 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -2142,6 +2142,11 @@ false + + + Type + + Key diff --git a/include/mainwindow.h b/include/mainwindow.h index 4eae446f..455e79eb 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -388,7 +388,7 @@ private: void redrawMetatileSelection(); QObjectList shortcutableObjects() const; - QTableWidgetItem * createNewCustomHeaderItem(QJsonValue value); + void addCustomHeaderValue(QString key, QJsonValue value, bool isNew = false); }; enum MapListUserRoles { diff --git a/src/editor.cpp b/src/editor.cpp index 50da1ca2..bf748b7c 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1951,30 +1951,34 @@ void Editor::updateCustomMapHeaderValues(QTableWidget *table) QMap fields; for (int row = 0; row < table->rowCount(); row++) { QString key = ""; - QString value = ""; - QTableWidgetItem *keyItem = table->item(row, 0); - QTableWidgetItem *valueItem = table->item(row, 1); + QTableWidgetItem *typeItem = table->item(row, 0); + QTableWidgetItem *keyItem = table->item(row, 1); + QTableWidgetItem *valueItem = table->item(row, 2); + if (keyItem) key = keyItem->text(); - if (!key.isEmpty() && valueItem) { - // Use the original table value to determine which type the input text should be saved as. - QJsonValue value = valueItem->data(Qt::UserRole).toJsonValue(); - switch (value.type()) - { - case QJsonValue::String: - value = QJsonValue(valueItem->text()); - break; - case QJsonValue::Double: - value = QJsonValue(valueItem->text().toInt()); - break; - case QJsonValue::Bool: - value = QJsonValue(valueItem->checkState() == Qt::Checked); - break; - default: - // Arrays and objects can't be updated via the table, just preserve the original value. - break; - } - fields[key] = value; + if (key.isEmpty() || !typeItem || !valueItem) + continue; + + // Read which JSON type to save the value as from the table data + QJsonValue::Type type = static_cast(typeItem->data(Qt::UserRole).toInt()); + QJsonValue value; + switch (type) + { + case QJsonValue::String: + value = QJsonValue(valueItem->text()); + break; + case QJsonValue::Double: + value = QJsonValue(valueItem->text().toInt()); + break; + case QJsonValue::Bool: + value = QJsonValue(valueItem->checkState() == Qt::Checked); + break; + default: + // All other types will just be preserved + value = valueItem->data(Qt::UserRole).toJsonValue(); + break; } + fields[key] = value; } map->customHeaders = fields; emit editedMapData(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 94055e76..e8787184 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -802,12 +802,8 @@ void MainWindow::displayMapProperties() { // Custom fields table. ui->tableWidget_CustomHeaderFields->blockSignals(true); ui->tableWidget_CustomHeaderFields->setRowCount(0); - for (auto it = map->customHeaders.begin(); it != map->customHeaders.end(); it++) { - int rowIndex = ui->tableWidget_CustomHeaderFields->rowCount(); - ui->tableWidget_CustomHeaderFields->insertRow(rowIndex); - ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 0, new QTableWidgetItem(it.key())); - ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 1, createNewCustomHeaderItem(it.value())); - } + for (auto it = map->customHeaders.begin(); it != map->customHeaders.end(); it++) + addCustomHeaderValue(it.key(), it.value()); ui->tableWidget_CustomHeaderFields->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); ui->tableWidget_CustomHeaderFields->blockSignals(false); } @@ -3080,36 +3076,65 @@ void MainWindow::togglePreferenceSpecificUi() { ui->actionOpen_Project_in_Text_Editor->setEnabled(true); } -QTableWidgetItem * MainWindow::createNewCustomHeaderItem(QJsonValue value) { - QTableWidgetItem * tableItem; - switch (value.type()) +void MainWindow::addCustomHeaderValue(QString key, QJsonValue value, bool isNew) { + QTableWidgetItem * valueItem; + QJsonValue::Type type = value.type(); + switch (type) { case QJsonValue::String: case QJsonValue::Double: - tableItem = new QTableWidgetItem(ParseUtil::jsonToQString(value)); + valueItem = new QTableWidgetItem(ParseUtil::jsonToQString(value)); break; case QJsonValue::Bool: - tableItem = new QTableWidgetItem(""); - tableItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked); + valueItem = new QTableWidgetItem(""); + valueItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked); break; default: - tableItem = new QTableWidgetItem("This value cannot be edited from this table"); - tableItem->setFlags(Qt::NoItemFlags); + valueItem = new QTableWidgetItem("This value cannot be edited from this table"); + valueItem->setFlags(Qt::NoItemFlags); + valueItem->setData(Qt::UserRole, value); // Preserve the value for writing to the file break; } - tableItem->setData(Qt::UserRole, value); // Save the original value/type for when it's written back to the project - return tableItem; + + const QHash typeToName = { + {QJsonValue::Bool, "Bool"}, + {QJsonValue::Double, "Number"}, + {QJsonValue::String, "String"}, + {QJsonValue::Array, "Array"}, + {QJsonValue::Object, "Object"}, + {QJsonValue::Null, "Null"}, + {QJsonValue::Undefined, "Null"}, + }; + QTableWidgetItem * typeItem = new QTableWidgetItem(typeToName[type]); + typeItem->setFlags(Qt::ItemIsEnabled); + typeItem->setData(Qt::UserRole, type); // Record the type for writing to the file + + int rowIndex = this->ui->tableWidget_CustomHeaderFields->rowCount(); + this->ui->tableWidget_CustomHeaderFields->insertRow(rowIndex); + this->ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 0, typeItem); + this->ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 1, new QTableWidgetItem(key)); + this->ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 2, valueItem); + + if (isNew) { + valueItem->setText(""); // Erase the "0" in new numbers + this->ui->tableWidget_CustomHeaderFields->selectRow(rowIndex); + this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields); + } } void MainWindow::on_pushButton_AddCustomHeaderField_clicked() { - int rowIndex = this->ui->tableWidget_CustomHeaderFields->rowCount(); - this->ui->tableWidget_CustomHeaderFields->insertRow(rowIndex); - this->ui->tableWidget_CustomHeaderFields->selectRow(rowIndex); - // TODO: New items default to string, allow type selection - QJsonValue defaultValue = QJsonValue(QString("")); - this->ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 1, createNewCustomHeaderItem(defaultValue)); - this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields); + const QMap valueTypes = { + {"String", QJsonValue(QString(""))}, + {"Number", QJsonValue(0)}, + {"Boolean", QJsonValue(false)}, + }; + + bool ok; + QStringList typeNames = valueTypes.keys(); + QString selection = QInputDialog::getItem(this, "", "Choose Value Type", typeNames, typeNames.indexOf("String"), false, &ok); + if (ok) + addCustomHeaderValue("", valueTypes[selection], true); } void MainWindow::on_pushButton_DeleteCustomHeaderField_clicked() From 67945cb2974b328e9297ce58007bc23d24464048 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sun, 16 Oct 2022 02:30:13 -0400 Subject: [PATCH 06/13] Preserve custom header arrays and objects --- include/lib/orderedjson.h | 5 +++++ src/lib/orderedjson.cpp | 27 +++++++++++++++++++++++++++ src/project.cpp | 23 +---------------------- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/include/lib/orderedjson.h b/include/lib/orderedjson.h index 20463cee..0b43080c 100644 --- a/include/lib/orderedjson.h +++ b/include/lib/orderedjson.h @@ -60,6 +60,9 @@ #include #include #include +#include +#include +#include #include #include @@ -129,6 +132,8 @@ public: int>::type = 0> Json(const V & v) : Json(array(v.begin(), v.end())) {} + static const Json fromQJsonValue(QJsonValue value); + // This prevents Json(some_pointer) from accidentally producing a bool. Use // Json(bool(some_pointer)) if that behavior is desired. Json(void *) = delete; diff --git a/src/lib/orderedjson.cpp b/src/lib/orderedjson.cpp index 699c8d12..025607ca 100644 --- a/src/lib/orderedjson.cpp +++ b/src/lib/orderedjson.cpp @@ -308,6 +308,33 @@ const Json & JsonArray::operator[] (int i) const { else return m_value[i]; } +const Json Json::fromQJsonValue(QJsonValue value) { + switch (value.type()) + { + default: + case QJsonValue::String: return value.toString(); + case QJsonValue::Double: return value.toInt(); + case QJsonValue::Bool: return value.toBool(); + case QJsonValue::Array: + { + QJsonArray qArr = value.toArray(); + Json::array arr; + for (const auto &i: qArr) + arr.push_back(Json::fromQJsonValue(i)); + return arr; + } + case QJsonValue::Object: + { + QJsonObject qObj = value.toObject(); + Json::object obj; + for (auto it = qObj.constBegin(); it != qObj.constEnd(); it++) + obj[it.key()] = Json::fromQJsonValue(it.value()); + return obj; + } + } +} + + /* * * * * * * * * * * * * * * * * * * * * Comparison */ diff --git a/src/project.cpp b/src/project.cpp index 6207fe5b..4df26f18 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1440,28 +1440,7 @@ void Project::saveMap(Map *map) { // Custom header fields. for (QString key : map->customHeaders.keys()) { - QJsonValue value = map->customHeaders[key]; - switch (value.type()) - { - default: - case QJsonValue::String: - mapObj[key] = value.toString(); - break; - case QJsonValue::Double: - mapObj[key] = value.toInt(); - break; - case QJsonValue::Bool: - mapObj[key] = value.toBool(); - break; - case QJsonValue::Array: - // TODO: Custom array values are replaced with empty strings - mapObj[key] = value.toString(); - break; - case QJsonValue::Object: - // TODO: Custom object values are replaced with empty strings - mapObj[key] = value.toString(); - break; - } + mapObj[key] = OrderedJson::fromQJsonValue(map->customHeaders[key]); } OrderedJson mapJson(mapObj); From a0eff32f361cc9efab6b40a11fe9c042f9c8c959 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sun, 16 Oct 2022 02:49:42 -0400 Subject: [PATCH 07/13] Remove more internal type conversions --- include/core/mapconnection.h | 2 +- include/core/maplayout.h | 8 +++---- include/ui/connectionpixmapitem.h | 2 +- src/core/map.cpp | 16 ++++++------- src/core/maplayout.cpp | 8 +++---- src/core/mapparser.cpp | 8 +++---- src/editor.cpp | 20 ++++++++-------- src/project.cpp | 38 +++++++++++++++---------------- src/ui/connectionpixmapitem.cpp | 2 +- src/ui/mapimageexporter.cpp | 2 +- src/ui/newmappopup.cpp | 24 +++++++++---------- 11 files changed, 65 insertions(+), 65 deletions(-) diff --git a/include/core/mapconnection.h b/include/core/mapconnection.h index b6be238e..11aa0e59 100644 --- a/include/core/mapconnection.h +++ b/include/core/mapconnection.h @@ -8,7 +8,7 @@ class MapConnection { public: QString direction; - QString offset; + int offset; QString map_name; }; diff --git a/include/core/maplayout.h b/include/core/maplayout.h index 888e5372..13215fff 100644 --- a/include/core/maplayout.h +++ b/include/core/maplayout.h @@ -14,10 +14,10 @@ public: static QString layoutConstantFromName(QString mapName); QString id; QString name; - QString width; - QString height; - QString border_width; - QString border_height; + int width; + int height; + int border_width; + int border_height; QString border_path; QString blockdata_path; QString tileset_primary_label; diff --git a/include/ui/connectionpixmapitem.h b/include/ui/connectionpixmapitem.h index a4cdf4e2..e12296af 100644 --- a/include/ui/connectionpixmapitem.h +++ b/include/ui/connectionpixmapitem.h @@ -15,7 +15,7 @@ public: setFlag(ItemSendsGeometryChanges); this->initialX = x; this->initialY = y; - this->initialOffset = connection->offset.toInt(); + this->initialOffset = connection->offset; this->baseMapWidth = baseMapWidth; this->baseMapHeight = baseMapHeight; } diff --git a/src/core/map.cpp b/src/core/map.cpp index 9bbe68c4..107033b3 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -310,10 +310,10 @@ void Map::setDimensions(int newWidth, int newHeight, bool setNewBlockdata, bool setNewDimensionsBlockdata(newWidth, newHeight); } - int oldWidth = layout->width.toInt(); - int oldHeight = layout->height.toInt(); - layout->width = QString::number(newWidth); - layout->height = QString::number(newHeight); + int oldWidth = layout->width; + int oldHeight = layout->height; + layout->width = newWidth; + layout->height = newHeight; if (enableScriptCallback && (oldWidth != newWidth || oldHeight != newHeight)) { Scripting::cb_MapResized(oldWidth, oldHeight, newWidth, newHeight); @@ -328,10 +328,10 @@ void Map::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata, setNewBorderDimensionsBlockdata(newWidth, newHeight); } - int oldWidth = layout->border_width.toInt(); - int oldHeight = layout->border_height.toInt(); - layout->border_width = QString::number(newWidth); - layout->border_height = QString::number(newHeight); + int oldWidth = layout->border_width; + int oldHeight = layout->border_height; + layout->border_width = newWidth; + layout->border_height = newHeight; if (enableScriptCallback && (oldWidth != newWidth || oldHeight != newHeight)) { Scripting::cb_BorderResized(oldWidth, oldHeight, newWidth, newHeight); diff --git a/src/core/maplayout.cpp b/src/core/maplayout.cpp index 8b1a1d3f..310017be 100644 --- a/src/core/maplayout.cpp +++ b/src/core/maplayout.cpp @@ -16,17 +16,17 @@ QString MapLayout::layoutConstantFromName(QString mapName) { } int MapLayout::getWidth() { - return width.toInt(nullptr, 0); + return width; } int MapLayout::getHeight() { - return height.toInt(nullptr, 0); + return height; } int MapLayout::getBorderWidth() { - return border_width.toInt(nullptr, 0); + return border_width; } int MapLayout::getBorderHeight() { - return border_height.toInt(nullptr, 0); + return border_height; } diff --git a/src/core/mapparser.cpp b/src/core/mapparser.cpp index 88592ab0..986c2c24 100644 --- a/src/core/mapparser.cpp +++ b/src/core/mapparser.cpp @@ -70,10 +70,10 @@ MapLayout *MapParser::parse(QString filepath, bool *error, Project *project) } MapLayout *mapLayout = new MapLayout(); - mapLayout->width = QString::number(mapWidth); - mapLayout->height = QString::number(mapHeight); - mapLayout->border_width = (borderWidth == 0) ? QString::number(2) : QString::number(borderWidth); - mapLayout->border_height = (borderHeight == 0) ? QString::number(2) : QString::number(borderHeight); + mapLayout->width = mapWidth; + mapLayout->height = mapHeight; + mapLayout->border_width = (borderWidth == 0) ? DEFAULT_BORDER_WIDTH : borderWidth; + mapLayout->border_height = (borderHeight == 0) ? DEFAULT_BORDER_HEIGHT : borderHeight; QList tilesets = project->tilesetLabelsOrdered; diff --git a/src/editor.cpp b/src/editor.cpp index bf748b7c..b00a5539 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -177,7 +177,7 @@ void Editor::setEditingConnections() { bool controlsEnabled = selected_connection_item != nullptr; setConnectionEditControlsEnabled(controlsEnabled); if (selected_connection_item) { - onConnectionOffsetChanged(selected_connection_item->connection->offset.toInt()); + onConnectionOffsetChanged(selected_connection_item->connection->offset); setConnectionMap(selected_connection_item->connection->map_name); setCurrentConnectionDirection(selected_connection_item->connection->direction); } @@ -775,7 +775,7 @@ void Editor::setCurrentConnectionDirection(QString curDirection) { selected_connection_item->connection->direction = curDirection; QPixmap pixmap = connected_map->renderConnection(*selected_connection_item->connection, map->layout); - int offset = selected_connection_item->connection->offset.toInt(nullptr, 0); + int offset = selected_connection_item->connection->offset; selected_connection_item->initialOffset = offset; int x = 0, y = 0; if (selected_connection_item->connection->direction == "up") { @@ -821,7 +821,7 @@ void Editor::updateCurrentConnectionDirection(QString curDirection) { void Editor::onConnectionMoved(MapConnection* connection) { updateMirroredConnectionOffset(connection); - onConnectionOffsetChanged(connection->offset.toInt()); + onConnectionOffsetChanged(connection->offset); maskNonVisibleConnectionTiles(); } @@ -835,7 +835,7 @@ void Editor::onConnectionOffsetChanged(int newOffset) { void Editor::setConnectionEditControlValues(MapConnection* connection) { QString mapName = connection ? connection->map_name : ""; QString direction = connection ? connection->direction : ""; - int offset = connection ? connection->offset.toInt() : 0; + int offset = connection ? connection->offset : 0; ui->comboBox_ConnectedMap->blockSignals(true); ui->comboBox_ConnectionDirection->blockSignals(true); @@ -884,7 +884,7 @@ void Editor::onConnectionItemSelected(ConnectionPixmapItem* connectionItem) { setConnectionEditControlValues(selected_connection_item->connection); ui->spinBox_ConnectionOffset->setMaximum(selected_connection_item->getMaxOffset()); ui->spinBox_ConnectionOffset->setMinimum(selected_connection_item->getMinOffset()); - onConnectionOffsetChanged(selected_connection_item->connection->offset.toInt()); + onConnectionOffsetChanged(selected_connection_item->connection->offset); } void Editor::setSelectedConnectionFromMap(QString mapName) { @@ -1561,7 +1561,7 @@ void Editor::createConnectionItem(MapConnection* connection, bool hide) { } QPixmap pixmap = connected_map->renderConnection(*connection, map->layout); - int offset = connection->offset.toInt(nullptr, 0); + int offset = connection->offset; int x = 0, y = 0; if (connection->direction == "up") { x = offset * 16; @@ -1724,7 +1724,7 @@ void Editor::updateConnectionOffset(int offset) { selected_connection_item->blockSignals(true); offset = qMin(offset, selected_connection_item->getMaxOffset()); offset = qMax(offset, selected_connection_item->getMinOffset()); - selected_connection_item->connection->offset = QString::number(offset); + selected_connection_item->connection->offset = offset; if (selected_connection_item->connection->direction == "up" || selected_connection_item->connection->direction == "down") { selected_connection_item->setX(selected_connection_item->initialX + (offset - selected_connection_item->initialOffset) * 16); } else if (selected_connection_item->connection->direction == "left" || selected_connection_item->connection->direction == "right") { @@ -1779,7 +1779,7 @@ void Editor::addNewConnection() { MapConnection* newConnection = new MapConnection; newConnection->direction = minDirection; - newConnection->offset = "0"; + newConnection->offset = 0; newConnection->map_name = defaultMapName; map->connections.append(newConnection); createConnectionItem(newConnection, true); @@ -1847,7 +1847,7 @@ void Editor::updateMirroredConnection(MapConnection* connection, QString origina otherMap->connections.append(mirrorConnection); } - mirrorConnection->offset = QString::number(-connection->offset.toInt()); + mirrorConnection->offset = -connection->offset; } void Editor::removeCurrentConnection() { @@ -1905,7 +1905,7 @@ void Editor::updateDiveEmergeMap(QString mapName, QString direction) { if (!connection) { connection = new MapConnection; connection->direction = direction; - connection->offset = "0"; + connection->offset = 0; connection->map_name = mapName; map->connections.append(connection); updateMirroredConnection(connection, connection->direction, connection->map_name); diff --git a/src/project.cpp b/src/project.cpp index 4df26f18..fb1e2800 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -567,29 +567,29 @@ bool Project::readMapLayouts() { logError(QString("Invalid layout 'width' value '%1' on layout %2 in %3. Must be greater than 0.").arg(lwidth).arg(i).arg(layoutsFilepath)); return false; } - layout->width = QString::number(lwidth); + layout->width = lwidth; int lheight = ParseUtil::jsonToInt(layoutObj["height"]); if (lheight <= 0) { logError(QString("Invalid layout 'height' value '%1' on layout %2 in %3. Must be greater than 0.").arg(lheight).arg(i).arg(layoutsFilepath)); return false; } - layout->height = QString::number(lheight); + layout->height = lheight; if (useCustomBorderSize) { int bwidth = ParseUtil::jsonToInt(layoutObj["border_width"]); if (bwidth <= 0) { // 0 is an expected border width/height that should be handled, GF used it for the RS layouts in FRLG logWarn(QString("Invalid layout 'border_width' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bwidth).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_WIDTH)); bwidth = DEFAULT_BORDER_WIDTH; } - layout->border_width = QString::number(bwidth); + layout->border_width = bwidth; int bheight = ParseUtil::jsonToInt(layoutObj["border_height"]); if (bheight <= 0) { logWarn(QString("Invalid layout 'border_height' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bheight).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_HEIGHT)); bheight = DEFAULT_BORDER_HEIGHT; } - layout->border_height = QString::number(bheight); + layout->border_height = bheight; } else { - layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); - layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); + layout->border_width = DEFAULT_BORDER_WIDTH; + layout->border_height = DEFAULT_BORDER_HEIGHT; } layout->tileset_primary_label = ParseUtil::jsonToQString(layoutObj["primary_tileset"]); if (layout->tileset_primary_label.isEmpty()) { @@ -641,11 +641,11 @@ void Project::saveMapLayouts() { OrderedJson::object layoutObj; layoutObj["id"] = layout->id; layoutObj["name"] = layout->name; - layoutObj["width"] = layout->width.toInt(nullptr, 0); - layoutObj["height"] = layout->height.toInt(nullptr, 0); + layoutObj["width"] = layout->width; + layoutObj["height"] = layout->height; if (useCustomBorderSize) { - layoutObj["border_width"] = layout->border_width.toInt(nullptr, 0); - layoutObj["border_height"] = layout->border_height.toInt(nullptr, 0); + layoutObj["border_width"] = layout->border_width; + layoutObj["border_height"] = layout->border_height; } layoutObj["primary_tileset"] = layout->tileset_primary_label; layoutObj["secondary_tileset"] = layout->tileset_secondary_label; @@ -672,10 +672,10 @@ void Project::setNewMapLayout(Map* map) { MapLayout *layout = new MapLayout(); layout->id = MapLayout::layoutConstantFromName(map->name); layout->name = QString("%1_Layout").arg(map->name); - layout->width = QString::number(getDefaultMapSize()); - layout->height = QString::number(getDefaultMapSize()); - layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); - layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); + layout->width = getDefaultMapSize(); + layout->height = getDefaultMapSize(); + layout->border_width = DEFAULT_BORDER_WIDTH; + layout->border_height = DEFAULT_BORDER_HEIGHT; layout->border_path = QString("%2%1/border.bin").arg(map->name).arg(projectConfig.getFilePath(ProjectFilePath::data_layouts_folders)); layout->blockdata_path = QString("%2%1/map.bin").arg(map->name).arg(projectConfig.getFilePath(ProjectFilePath::data_layouts_folders)); layout->tileset_primary_label = tilesetLabels["primary"].value(0, "gTileset_General"); @@ -1311,11 +1311,11 @@ void Project::saveMap(Map *map) { QJsonObject newLayoutObj; newLayoutObj["id"] = map->layout->id; newLayoutObj["name"] = map->layout->name; - newLayoutObj["width"] = map->layout->width.toInt(); - newLayoutObj["height"] = map->layout->height.toInt(); + newLayoutObj["width"] = map->layout->width; + newLayoutObj["height"] = map->layout->height; if (projectConfig.getUseCustomBorderSize()) { - newLayoutObj["border_width"] = map->layout->border_width.toInt(); - newLayoutObj["border_height"] = map->layout->border_height.toInt(); + newLayoutObj["border_width"] = map->layout->border_width; + newLayoutObj["border_height"] = map->layout->border_height; } newLayoutObj["primary_tileset"] = map->layout->tileset_primary_label; newLayoutObj["secondary_tileset"] = map->layout->tileset_secondary_label; @@ -1361,7 +1361,7 @@ void Project::saveMap(Map *map) { if (mapNamesToMapConstants.contains(connection->map_name)) { OrderedJson::object connectionObj; connectionObj["direction"] = connection->direction; - connectionObj["offset"] = connection->offset.toInt(); + connectionObj["offset"] = connection->offset; connectionObj["map"] = this->mapNamesToMapConstants.value(connection->map_name); connectionsArr.append(connectionObj); } else { diff --git a/src/ui/connectionpixmapitem.cpp b/src/ui/connectionpixmapitem.cpp index 221c1911..3fd09dda 100644 --- a/src/ui/connectionpixmapitem.cpp +++ b/src/ui/connectionpixmapitem.cpp @@ -56,7 +56,7 @@ QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVari y = this->initialY; } - this->connection->offset = QString::number(newOffset); + this->connection->offset = newOffset; emit connectionMoved(this->connection); return QPointF(x, y); } diff --git a/src/ui/mapimageexporter.cpp b/src/ui/mapimageexporter.cpp index d78ac427..b8813258 100644 --- a/src/ui/mapimageexporter.cpp +++ b/src/ui/mapimageexporter.cpp @@ -241,7 +241,7 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress, bool inclu continue; int x = cur.x; int y = cur.y; - int offset = connection->offset.toInt(nullptr, 0); + int offset = connection->offset; Map *connectionMap = this->editor->project->loadMap(connection->map_name); if (connection->direction == "up") { x += offset; diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index 8cd41b5a..1165b416 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -118,8 +118,8 @@ void NewMapPopup::setDefaultValues(int groupNum, QString mapSec) { ui->comboBox_Song->addItems(project->songNames); if (existingLayout) { - ui->spinBox_NewMap_Width->setValue(project->mapLayouts.value(layoutId)->width.toInt(nullptr, 0)); - ui->spinBox_NewMap_Height->setValue(project->mapLayouts.value(layoutId)->height.toInt(nullptr, 0)); + ui->spinBox_NewMap_Width->setValue(project->mapLayouts.value(layoutId)->width); + ui->spinBox_NewMap_Height->setValue(project->mapLayouts.value(layoutId)->height); ui->comboBox_NewMap_Primary_Tileset->setCurrentText(project->mapLayouts.value(layoutId)->tileset_primary_label); ui->comboBox_NewMap_Secondary_Tileset->setCurrentText(project->mapLayouts.value(layoutId)->tileset_secondary_label); ui->spinBox_NewMap_Width->setDisabled(true); @@ -156,8 +156,8 @@ void NewMapPopup::setDefaultValuesImportMap(MapLayout *mapLayout) { ui->comboBox_Song->addItems(project->songNames); - ui->spinBox_NewMap_Width->setValue(mapLayout->width.toInt(nullptr, 0)); - ui->spinBox_NewMap_Height->setValue(mapLayout->height.toInt(nullptr, 0)); + ui->spinBox_NewMap_Width->setValue(mapLayout->width); + ui->spinBox_NewMap_Height->setValue(mapLayout->height); ui->comboBox_NewMap_Primary_Tileset->setCurrentText(mapLayout->tileset_primary_label); ui->comboBox_NewMap_Secondary_Tileset->setCurrentText(mapLayout->tileset_secondary_label); @@ -208,8 +208,8 @@ void NewMapPopup::setDefaultValuesProjectConfig(bool importedMap, MapLayout *map } if (projectConfig.getUseCustomBorderSize()) { if (importedMap) { - ui->spinBox_NewMap_BorderWidth->setValue(mapLayout->border_width.toInt(nullptr, 0)); - ui->spinBox_NewMap_BorderHeight->setValue(mapLayout->border_height.toInt(nullptr, 0)); + ui->spinBox_NewMap_BorderWidth->setValue(mapLayout->border_width); + ui->spinBox_NewMap_BorderHeight->setValue(mapLayout->border_height); } ui->spinBox_NewMap_BorderWidth->setVisible(true); ui->spinBox_NewMap_BorderHeight->setVisible(true); @@ -278,14 +278,14 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { layout = new MapLayout; layout->id = MapLayout::layoutConstantFromName(newMapName); layout->name = QString("%1_Layout").arg(newMap->name); - layout->width = QString::number(this->ui->spinBox_NewMap_Width->value()); - layout->height = QString::number(this->ui->spinBox_NewMap_Height->value()); + layout->width = this->ui->spinBox_NewMap_Width->value(); + layout->height = this->ui->spinBox_NewMap_Height->value(); if (projectConfig.getUseCustomBorderSize()) { - layout->border_width = QString::number(this->ui->spinBox_NewMap_BorderWidth->value()); - layout->border_height = QString::number(this->ui->spinBox_NewMap_BorderHeight->value()); + layout->border_width = this->ui->spinBox_NewMap_BorderWidth->value(); + layout->border_height = this->ui->spinBox_NewMap_BorderHeight->value(); } else { - layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); - layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); + layout->border_width = DEFAULT_BORDER_WIDTH; + layout->border_height = DEFAULT_BORDER_HEIGHT; } layout->tileset_primary_label = this->ui->comboBox_NewMap_Primary_Tileset->currentText(); layout->tileset_secondary_label = this->ui->comboBox_NewMap_Secondary_Tileset->currentText(); From 5e83c1f716b192de2f6d3a15ede868d678389f0e Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 17 Oct 2022 14:52:12 -0400 Subject: [PATCH 08/13] WIP Adjust custom attributes table --- forms/mainwindow.ui | 2 +- src/editor.cpp | 2 +- src/mainwindow.cpp | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index 1a2268a2..05ece2f1 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -2125,7 +2125,7 @@ Custom fields will be added to the map.json file for the current map. - false + true false diff --git a/src/editor.cpp b/src/editor.cpp index b00a5539..46a729fc 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1959,7 +1959,7 @@ void Editor::updateCustomMapHeaderValues(QTableWidget *table) if (key.isEmpty() || !typeItem || !valueItem) continue; - // Read which JSON type to save the value as from the table data + // Read from the table data which JSON type to save the value as QJsonValue::Type type = static_cast(typeItem->data(Qt::UserRole).toInt()); QJsonValue value; switch (type) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e8787184..451a5216 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3088,10 +3088,11 @@ void MainWindow::addCustomHeaderValue(QString key, QJsonValue value, bool isNew) case QJsonValue::Bool: valueItem = new QTableWidgetItem(""); valueItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked); + valueItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); break; default: valueItem = new QTableWidgetItem("This value cannot be edited from this table"); - valueItem->setFlags(Qt::NoItemFlags); + valueItem->setFlags(Qt::ItemIsSelectable); valueItem->setData(Qt::UserRole, value); // Preserve the value for writing to the file break; } @@ -3108,6 +3109,7 @@ void MainWindow::addCustomHeaderValue(QString key, QJsonValue value, bool isNew) QTableWidgetItem * typeItem = new QTableWidgetItem(typeToName[type]); typeItem->setFlags(Qt::ItemIsEnabled); typeItem->setData(Qt::UserRole, type); // Record the type for writing to the file + typeItem->setTextAlignment(Qt::AlignCenter); int rowIndex = this->ui->tableWidget_CustomHeaderFields->rowCount(); this->ui->tableWidget_CustomHeaderFields->insertRow(rowIndex); From 75788ed3f9d46e6eb9b92b46cad80af0d53f40e1 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 17 Oct 2022 22:37:06 -0400 Subject: [PATCH 09/13] Convert event JSON values by type --- src/core/events.cpp | 97 +++++++++++++++++++++++---------------------- src/project.cpp | 7 ++-- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/core/events.cpp b/src/core/events.cpp index a7b03b53..9a8585d8 100644 --- a/src/core/events.cpp +++ b/src/core/events.cpp @@ -38,6 +38,7 @@ void Event::setDefaultValues(Project *) { this->setElevation(3); } +// TODO: Don't assume string type void Event::readCustomValues(QJsonObject values) { this->customValues.clear(); QSet expectedFields = this->getExpectedFields(); @@ -163,17 +164,17 @@ OrderedJson::object ObjectEvent::buildEventJson(Project *) { } bool ObjectEvent::loadFromJson(QJsonObject json, Project *) { - this->setX(json["x"].toInt()); - this->setY(json["y"].toInt()); - this->setElevation(json["elevation"].toInt()); - this->setGfx(json["graphics_id"].toString()); - this->setMovement(json["movement_type"].toString()); - this->setRadiusX(json["movement_range_x"].toInt()); - this->setRadiusY(json["movement_range_y"].toInt()); - this->setTrainerType(json["trainer_type"].toString()); - this->setSightRadiusBerryTreeID(json["trainer_sight_or_berry_tree_id"].toString()); - this->setScript(json["script"].toString()); - this->setFlag(json["flag"].toString()); + this->setX(ParseUtil::jsonToInt(json["x"])); + this->setY(ParseUtil::jsonToInt(json["y"])); + this->setElevation(ParseUtil::jsonToInt(json["elevation"])); + this->setGfx(ParseUtil::jsonToQString(json["graphics_id"])); + this->setMovement(ParseUtil::jsonToQString(json["movement_type"])); + this->setRadiusX(ParseUtil::jsonToInt(json["movement_range_x"])); + this->setRadiusY(ParseUtil::jsonToInt(json["movement_range_y"])); + this->setTrainerType(ParseUtil::jsonToQString(json["trainer_type"])); + this->setSightRadiusBerryTreeID(ParseUtil::jsonToQString(json["trainer_sight_or_berry_tree_id"])); + this->setScript(ParseUtil::jsonToQString(json["script"])); + this->setFlag(ParseUtil::jsonToQString(json["flag"])); this->readCustomValues(json); @@ -220,7 +221,7 @@ void ObjectEvent::loadPixmap(Project *project) { // Invalid gfx constant. // If this is a number, try to use that instead. bool ok; - int altGfx = this->gfx.toInt(&ok); + int altGfx = ParseUtil::gameStringToInt(this->gfx, &ok); if (ok && (altGfx < project->gfxDefines.count())) { eventGfx = project->eventGraphicsMap.value(project->gfxDefines.key(altGfx, "NULL"), nullptr); } @@ -311,13 +312,13 @@ OrderedJson::object CloneObjectEvent::buildEventJson(Project *project) { } bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) { - this->setX(json["x"].toInt()); - this->setY(json["y"].toInt()); - this->setGfx(json["graphics_id"].toString()); - this->setTargetID(json["target_local_id"].toInt()); + this->setX(ParseUtil::jsonToInt(json["x"])); + this->setY(ParseUtil::jsonToInt(json["y"])); + this->setGfx(ParseUtil::jsonToQString(json["graphics_id"])); + this->setTargetID(ParseUtil::jsonToInt(json["target_local_id"])); // Ensure the target map constant is valid before adding it to the events. - QString mapConstant = json["target_map"].toString(); + QString mapConstant = ParseUtil::jsonToQString(json["target_map"]); if (project->mapConstantsToMapNames.contains(mapConstant)) { this->setTargetMap(project->mapConstantsToMapNames.value(mapConstant)); } else if (mapConstant == NONE_MAP_CONSTANT) { @@ -421,13 +422,13 @@ OrderedJson::object WarpEvent::buildEventJson(Project *project) { } bool WarpEvent::loadFromJson(QJsonObject json, Project *project) { - this->setX(json["x"].toInt()); - this->setY(json["y"].toInt()); - this->setElevation(json["elevation"].toInt()); - this->setDestinationWarpID(json["dest_warp_id"].toInt()); + this->setX(ParseUtil::jsonToInt(json["x"])); + this->setY(ParseUtil::jsonToInt(json["y"])); + this->setElevation(ParseUtil::jsonToInt(json["elevation"])); + this->setDestinationWarpID(ParseUtil::jsonToInt(json["dest_warp_id"])); // Ensure the warp destination map constant is valid before adding it to the warps. - QString mapConstant = json["dest_map"].toString(); + QString mapConstant = ParseUtil::jsonToQString(json["dest_map"]); if (project->mapConstantsToMapNames.contains(mapConstant)) { this->setDestinationMap(project->mapConstantsToMapNames.value(mapConstant)); } else if (mapConstant == NONE_MAP_CONSTANT) { @@ -515,12 +516,12 @@ OrderedJson::object TriggerEvent::buildEventJson(Project *) { } bool TriggerEvent::loadFromJson(QJsonObject json, Project *) { - this->setX(json["x"].toInt()); - this->setY(json["y"].toInt()); - this->setElevation(json["elevation"].toInt()); - this->setScriptVar(json["var"].toString()); - this->setScriptVarValue(json["var_value"].toString()); - this->setScriptLabel(json["script"].toString()); + this->setX(ParseUtil::jsonToInt(json["x"])); + this->setY(ParseUtil::jsonToInt(json["y"])); + this->setElevation(ParseUtil::jsonToInt(json["elevation"])); + this->setScriptVar(ParseUtil::jsonToQString(json["var"])); + this->setScriptVarValue(ParseUtil::jsonToQString(json["var_value"])); + this->setScriptLabel(ParseUtil::jsonToQString(json["script"])); this->readCustomValues(json); @@ -589,10 +590,10 @@ OrderedJson::object WeatherTriggerEvent::buildEventJson(Project *) { } bool WeatherTriggerEvent::loadFromJson(QJsonObject json, Project *) { - this->setX(json["x"].toInt()); - this->setY(json["y"].toInt()); - this->setElevation(json["elevation"].toInt()); - this->setWeather(json["weather"].toString()); + this->setX(ParseUtil::jsonToInt(json["x"])); + this->setY(ParseUtil::jsonToInt(json["y"])); + this->setElevation(ParseUtil::jsonToInt(json["elevation"])); + this->setWeather(ParseUtil::jsonToQString(json["weather"])); this->readCustomValues(json); @@ -665,11 +666,11 @@ OrderedJson::object SignEvent::buildEventJson(Project *) { } bool SignEvent::loadFromJson(QJsonObject json, Project *) { - this->setX(json["x"].toInt()); - this->setY(json["y"].toInt()); - this->setElevation(json["elevation"].toInt()); - this->setFacingDirection(json["player_facing_dir"].toString()); - this->setScriptLabel(json["script"].toString()); + this->setX(ParseUtil::jsonToInt(json["x"])); + this->setY(ParseUtil::jsonToInt(json["y"])); + this->setElevation(ParseUtil::jsonToInt(json["elevation"])); + this->setFacingDirection(ParseUtil::jsonToQString(json["player_facing_dir"])); + this->setScriptLabel(ParseUtil::jsonToQString(json["script"])); this->readCustomValues(json); @@ -746,16 +747,16 @@ OrderedJson::object HiddenItemEvent::buildEventJson(Project *) { } bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) { - this->setX(json["x"].toInt()); - this->setY(json["y"].toInt()); - this->setElevation(json["elevation"].toInt()); - this->setItem(json["item"].toString()); - this->setFlag(json["flag"].toString()); + this->setX(ParseUtil::jsonToInt(json["x"])); + this->setY(ParseUtil::jsonToInt(json["y"])); + this->setElevation(ParseUtil::jsonToInt(json["elevation"])); + this->setItem(ParseUtil::jsonToQString(json["item"])); + this->setFlag(ParseUtil::jsonToQString(json["flag"])); if (projectConfig.getHiddenItemQuantityEnabled()) { - this->setQuantity(json["quantity"].toInt()); + this->setQuantity(ParseUtil::jsonToInt(json["quantity"])); } if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { - this->setUnderfoot(json["underfoot"].toBool()); + this->setUnderfoot(ParseUtil::jsonToBool(json["underfoot"])); } this->readCustomValues(json); @@ -834,10 +835,10 @@ OrderedJson::object SecretBaseEvent::buildEventJson(Project *) { } bool SecretBaseEvent::loadFromJson(QJsonObject json, Project *) { - this->setX(json["x"].toInt()); - this->setY(json["y"].toInt()); - this->setElevation(json["elevation"].toInt()); - this->setBaseID(json["secret_base_id"].toString()); + this->setX(ParseUtil::jsonToInt(json["x"])); + this->setY(ParseUtil::jsonToInt(json["y"])); + this->setElevation(ParseUtil::jsonToInt(json["elevation"])); + this->setBaseID(ParseUtil::jsonToQString(json["secret_base_id"])); this->readCustomValues(json); diff --git a/src/project.cpp b/src/project.cpp index 36b98110..3ce93261 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -160,7 +160,6 @@ const QSet defaultTopLevelMapFields = { "bg_events", "shared_events_map", "shared_scripts_map", - "test", }; QSet Project::getTopLevelMapFields() { @@ -218,7 +217,7 @@ bool Project::loadMapData(Map* map) { for (int i = 0; i < objectEventsArr.size(); i++) { QJsonObject event = objectEventsArr[i].toObject(); // If clone objects are not enabled then no type field is present - QString type = hasCloneObjects ? event["type"].toString() : "object"; + QString type = hasCloneObjects ? ParseUtil::jsonToQString(event["type"]) : "object"; if (type.isEmpty() || type == "object") { ObjectEvent *object = new ObjectEvent(); object->loadFromJson(event, this); @@ -253,7 +252,7 @@ bool Project::loadMapData(Map* map) { QJsonArray coordEventsArr = mapObj["coord_events"].toArray(); for (int i = 0; i < coordEventsArr.size(); i++) { QJsonObject event = coordEventsArr[i].toObject(); - QString type = event["type"].toString(); + QString type = ParseUtil::jsonToQString(event["type"]); if (type == "trigger") { TriggerEvent *coord = new TriggerEvent(); coord->loadFromJson(event, this); @@ -271,7 +270,7 @@ bool Project::loadMapData(Map* map) { QJsonArray bgEventsArr = mapObj["bg_events"].toArray(); for (int i = 0; i < bgEventsArr.size(); i++) { QJsonObject event = bgEventsArr[i].toObject(); - QString type = event["type"].toString(); + QString type = ParseUtil::jsonToQString(event["type"]); if (type == "sign") { SignEvent *bg = new SignEvent(); bg->loadFromJson(event, this); From 0e0da77c074e4d1d5984d5a572cffa513293ffaa Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 18 Oct 2022 12:39:37 -0400 Subject: [PATCH 10/13] NONE_MAP -> DYNAMIC_MAP --- include/project.h | 5 +++-- src/core/events.cpp | 8 ++++---- src/editor.cpp | 4 ++-- src/project.cpp | 6 +++--- src/ui/draggablepixmapitem.cpp | 6 +++--- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/project.h b/include/project.h index a844b225..e76cfb0f 100644 --- a/include/project.h +++ b/include/project.h @@ -26,8 +26,9 @@ struct EventGraphics bool inanimate; }; -static QString NONE_MAP_CONSTANT = "MAP_NONE"; -static QString NONE_MAP_NAME = "None"; +// The constant and displayed name of the special map value used by warps with multiple potential destinations +static QString DYNAMIC_MAP_CONSTANT = "MAP_DYNAMIC"; +static QString DYNAMIC_MAP_NAME = "Dynamic"; class Project : public QObject { diff --git a/src/core/events.cpp b/src/core/events.cpp index 9a8585d8..7f15997b 100644 --- a/src/core/events.cpp +++ b/src/core/events.cpp @@ -321,8 +321,8 @@ bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) { QString mapConstant = ParseUtil::jsonToQString(json["target_map"]); if (project->mapConstantsToMapNames.contains(mapConstant)) { this->setTargetMap(project->mapConstantsToMapNames.value(mapConstant)); - } else if (mapConstant == NONE_MAP_CONSTANT) { - this->setTargetMap(NONE_MAP_NAME); + } else if (mapConstant == DYNAMIC_MAP_CONSTANT) { + this->setTargetMap(DYNAMIC_MAP_NAME); } else { logError(QString("Destination map constant '%1' is invalid").arg(mapConstant)); return false; @@ -431,8 +431,8 @@ bool WarpEvent::loadFromJson(QJsonObject json, Project *project) { QString mapConstant = ParseUtil::jsonToQString(json["dest_map"]); if (project->mapConstantsToMapNames.contains(mapConstant)) { this->setDestinationMap(project->mapConstantsToMapNames.value(mapConstant)); - } else if (mapConstant == NONE_MAP_CONSTANT) { - this->setDestinationMap(NONE_MAP_NAME); + } else if (mapConstant == DYNAMIC_MAP_CONSTANT) { + this->setDestinationMap(DYNAMIC_MAP_NAME); } else { logError(QString("Destination map constant '%1' is invalid for warp").arg(mapConstant)); return false; diff --git a/src/editor.cpp b/src/editor.cpp index 883eaa30..98000854 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1747,7 +1747,7 @@ void Editor::setConnectionMap(QString mapName) { if (!selected_connection_item) return; - if (mapName.isEmpty() || mapName == NONE_MAP_NAME) { + if (mapName.isEmpty() || mapName == DYNAMIC_MAP_NAME) { removeCurrentConnection(); return; } @@ -1899,7 +1899,7 @@ void Editor::updateDiveEmergeMap(QString mapName, QString direction) { } } - if (mapName.isEmpty() || mapName == NONE_MAP_NAME) { + if (mapName.isEmpty() || mapName == DYNAMIC_MAP_NAME) { // Remove dive/emerge connection if (connection) { map->connections.removeOne(connection); diff --git a/src/project.cpp b/src/project.cpp index 3ce93261..e56dd8eb 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1762,9 +1762,9 @@ bool Project::readMapGroups() { } } - mapConstantsToMapNames.insert(NONE_MAP_CONSTANT, NONE_MAP_NAME); - mapNamesToMapConstants.insert(NONE_MAP_NAME, NONE_MAP_CONSTANT); - maps.append(NONE_MAP_NAME); + mapConstantsToMapNames.insert(DYNAMIC_MAP_CONSTANT, DYNAMIC_MAP_NAME); + mapNamesToMapConstants.insert(DYNAMIC_MAP_NAME, DYNAMIC_MAP_CONSTANT); + maps.append(DYNAMIC_MAP_NAME); groupNames = groups; groupedMapNames = groupedMaps; diff --git a/src/ui/draggablepixmapitem.cpp b/src/ui/draggablepixmapitem.cpp index ef749a07..5bd042a8 100644 --- a/src/ui/draggablepixmapitem.cpp +++ b/src/ui/draggablepixmapitem.cpp @@ -85,14 +85,14 @@ void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) { if (eventType == Event::Type::Warp) { WarpEvent *warp = dynamic_cast(this->event); QString destMap = warp->getDestinationMap(); - if (destMap != NONE_MAP_NAME) { + if (destMap != DYNAMIC_MAP_NAME) { emit editor->warpEventDoubleClicked(destMap, warp->getDestinationWarpID(), Event::Group::Warp); } } else if (eventType == Event::Type::CloneObject) { CloneObjectEvent *clone = dynamic_cast(this->event); QString destMap = clone->getTargetMap(); - if (destMap != NONE_MAP_NAME) { + if (destMap != DYNAMIC_MAP_NAME) { emit editor->warpEventDoubleClicked(destMap, clone->getTargetID(), Event::Group::Object); } } @@ -100,7 +100,7 @@ void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) { SecretBaseEvent *base = dynamic_cast(this->event); QString baseId = base->getBaseID(); QString destMap = editor->project->mapConstantsToMapNames.value("MAP_" + baseId.left(baseId.lastIndexOf("_"))); - if (destMap != NONE_MAP_NAME) { + if (destMap != DYNAMIC_MAP_NAME) { emit editor->warpEventDoubleClicked(destMap, 0, Event::Group::Warp); } } From 8e6585bbb2924358e473828967d851af1ec0ee39 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 18 Oct 2022 13:44:45 -0400 Subject: [PATCH 11/13] Treat warp IDs as strings, stop deleting invalid warps --- include/core/events.h | 7 ++++--- include/mainwindow.h | 1 + include/ui/eventframes.h | 2 +- src/core/events.cpp | 29 ++++++++++++++++++++------ src/mainwindow.cpp | 38 ++++++++++++++++++---------------- src/ui/draggablepixmapitem.cpp | 15 +++++--------- src/ui/eventframes.cpp | 14 ++++++------- 7 files changed, 61 insertions(+), 45 deletions(-) diff --git a/include/core/events.h b/include/core/events.h index 51e82340..a31ca8a5 100644 --- a/include/core/events.h +++ b/include/core/events.h @@ -173,6 +173,7 @@ public: int getEventIndex(); + static QString eventGroupToString(Event::Group group); static QString eventTypeToString(Event::Type type); static Event::Type eventTypeFromString(QString type); @@ -340,12 +341,12 @@ public: void setDestinationMap(QString newDestinationMap) { this->destinationMap = newDestinationMap; } QString getDestinationMap() { return this->destinationMap; } - void setDestinationWarpID(int newDestinationWarpID) { this->destinationWarpID = newDestinationWarpID; } - int getDestinationWarpID() { return this->destinationWarpID; } + void setDestinationWarpID(QString newDestinationWarpID) { this->destinationWarpID = newDestinationWarpID; } + QString getDestinationWarpID() { return this->destinationWarpID; } private: QString destinationMap; - int destinationWarpID = 0; + QString destinationWarpID; }; diff --git a/include/mainwindow.h b/include/mainwindow.h index 34915653..b8653d58 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -219,6 +219,7 @@ private slots: void on_toolButton_deleteObject_clicked(); void addNewEvent(Event::Type type); + void tryAddEventTab(QWidget * tab, Event::Group group); void displayEventTabs(); void updateSelectedObjects(); void updateObjects(); diff --git a/include/ui/eventframes.h b/include/ui/eventframes.h index 181ac141..a85a8f08 100644 --- a/include/ui/eventframes.h +++ b/include/ui/eventframes.h @@ -133,7 +133,7 @@ public: public: NoScrollComboBox *combo_dest_map; - NoScrollSpinBox *spinner_dest_warp; + NoScrollComboBox *combo_dest_warp; private: WarpEvent *warp; diff --git a/src/core/events.cpp b/src/core/events.cpp index 7f15997b..c61c86b6 100644 --- a/src/core/events.cpp +++ b/src/core/events.cpp @@ -61,6 +61,23 @@ void Event::modify() { this->map->modify(); } +QString Event::eventGroupToString(Event::Group group) { + switch (group) { + case Event::Group::Object: + return "Object"; + case Event::Group::Warp: + return "Warp"; + case Event::Group::Coord: + return "Trigger"; + case Event::Group::Bg: + return "BG"; + case Event::Group::Heal: + return "Healspot"; + default: + return ""; + } +} + QString Event::eventTypeToString(Event::Type type) { switch (type) { case Event::Type::Object: @@ -324,8 +341,8 @@ bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) { } else if (mapConstant == DYNAMIC_MAP_CONSTANT) { this->setTargetMap(DYNAMIC_MAP_NAME); } else { - logError(QString("Destination map constant '%1' is invalid").arg(mapConstant)); - return false; + logWarn(QString("Target Map constant '%1' is invalid. Using default '%2'.").arg(mapConstant).arg(DYNAMIC_MAP_CONSTANT)); + this->setTargetMap(DYNAMIC_MAP_NAME); } this->readCustomValues(json); @@ -425,7 +442,7 @@ bool WarpEvent::loadFromJson(QJsonObject json, Project *project) { this->setX(ParseUtil::jsonToInt(json["x"])); this->setY(ParseUtil::jsonToInt(json["y"])); this->setElevation(ParseUtil::jsonToInt(json["elevation"])); - this->setDestinationWarpID(ParseUtil::jsonToInt(json["dest_warp_id"])); + this->setDestinationWarpID(ParseUtil::jsonToQString(json["dest_warp_id"])); // Ensure the warp destination map constant is valid before adding it to the warps. QString mapConstant = ParseUtil::jsonToQString(json["dest_map"]); @@ -434,8 +451,8 @@ bool WarpEvent::loadFromJson(QJsonObject json, Project *project) { } else if (mapConstant == DYNAMIC_MAP_CONSTANT) { this->setDestinationMap(DYNAMIC_MAP_NAME); } else { - logError(QString("Destination map constant '%1' is invalid for warp").arg(mapConstant)); - return false; + logWarn(QString("Destination Map constant '%1' is invalid. Using default '%2'.").arg(mapConstant).arg(DYNAMIC_MAP_CONSTANT)); + this->setDestinationMap(DYNAMIC_MAP_NAME); } this->readCustomValues(json); @@ -445,7 +462,7 @@ bool WarpEvent::loadFromJson(QJsonObject json, Project *project) { void WarpEvent::setDefaultValues(Project *) { if (this->getMap()) this->setDestinationMap(this->getMap()->name); - this->setDestinationWarpID(0); + this->setDestinationWarpID("0"); this->setElevation(0); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 19e5d1b4..fb4c307e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -719,6 +719,10 @@ void MainWindow::refreshMapScene() } void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_group) { + // Can't warp to dynamic maps + if (map_name == DYNAMIC_MAP_NAME) + return; + // Ensure valid destination map name. if (!editor->project->mapNames.contains(map_name)) { logError(QString("Invalid map name '%1'").arg(map_name)); @@ -737,10 +741,10 @@ void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_ } // Select the target event. - event_id -= Event::getIndexOffset(event_group); + int index = event_id - Event::getIndexOffset(event_group); QList events = editor->map->events[event_group]; - if (event_id < events.length() && event_id >= 0) { - Event *event = events.at(event_id); + if (index < events.length() && index >= 0) { + Event *event = events.at(index); for (DraggablePixmapItem *item : editor->getObjects()) { if (item->event == event) { editor->selected_events->clear(); @@ -748,6 +752,9 @@ void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_ editor->updateSelectedEvents(); } } + } else { + // Can still warp to this map, but can't select the specified event + logWarn(QString("%1 %2 doesn't exist on map '%3'").arg(Event::eventGroupToString(event_group)).arg(event_id).arg(map_name)); } } @@ -1884,25 +1891,20 @@ void MainWindow::addNewEvent(Event::Type type) { } } +void MainWindow::tryAddEventTab(QWidget * tab, Event::Group group) { + if (editor->map->events.value(group).length()) + ui->tabWidget_EventType->addTab(tab, QString("%1s").arg(Event::eventGroupToString(group))); +} + void MainWindow::displayEventTabs() { const QSignalBlocker blocker(ui->tabWidget_EventType); ui->tabWidget_EventType->clear(); - - if (editor->map->events.value(Event::Group::Object).length()) - ui->tabWidget_EventType->addTab(eventTabObjectWidget, "Objects"); - - if (editor->map->events.value(Event::Group::Warp).length()) - ui->tabWidget_EventType->addTab(eventTabWarpWidget, "Warps"); - - if (editor->map->events.value(Event::Group::Coord).length()) - ui->tabWidget_EventType->addTab(eventTabTriggerWidget, "Triggers"); - - if (editor->map->events.value(Event::Group::Bg).length()) - ui->tabWidget_EventType->addTab(eventTabBGWidget, "BGs"); - - if (editor->map->events.value(Event::Group::Heal).length()) - ui->tabWidget_EventType->addTab(eventTabHealspotWidget, "Healspots"); + tryAddEventTab(eventTabObjectWidget, Event::Group::Object); + tryAddEventTab(eventTabWarpWidget, Event::Group::Warp); + tryAddEventTab(eventTabTriggerWidget, Event::Group::Coord); + tryAddEventTab(eventTabBGWidget, Event::Group::Bg); + tryAddEventTab(eventTabHealspotWidget, Event::Group::Heal); } void MainWindow::updateObjects() { diff --git a/src/ui/draggablepixmapitem.cpp b/src/ui/draggablepixmapitem.cpp index 5bd042a8..d06c9786 100644 --- a/src/ui/draggablepixmapitem.cpp +++ b/src/ui/draggablepixmapitem.cpp @@ -85,23 +85,18 @@ void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) { if (eventType == Event::Type::Warp) { WarpEvent *warp = dynamic_cast(this->event); QString destMap = warp->getDestinationMap(); - if (destMap != DYNAMIC_MAP_NAME) { - emit editor->warpEventDoubleClicked(destMap, warp->getDestinationWarpID(), Event::Group::Warp); - } + bool ok; + int warpId = ParseUtil::gameStringToInt(warp->getDestinationWarpID(), &ok); + if (ok) emit editor->warpEventDoubleClicked(destMap, warpId, Event::Group::Warp); } else if (eventType == Event::Type::CloneObject) { CloneObjectEvent *clone = dynamic_cast(this->event); - QString destMap = clone->getTargetMap(); - if (destMap != DYNAMIC_MAP_NAME) { - emit editor->warpEventDoubleClicked(destMap, clone->getTargetID(), Event::Group::Object); - } + emit editor->warpEventDoubleClicked(clone->getTargetMap(), clone->getTargetID(), Event::Group::Object); } else if (eventType == Event::Type::SecretBase) { SecretBaseEvent *base = dynamic_cast(this->event); QString baseId = base->getBaseID(); QString destMap = editor->project->mapConstantsToMapNames.value("MAP_" + baseId.left(baseId.lastIndexOf("_"))); - if (destMap != DYNAMIC_MAP_NAME) { - emit editor->warpEventDoubleClicked(destMap, 0, Event::Group::Warp); - } + emit editor->warpEventDoubleClicked(destMap, 0, Event::Group::Warp); } } diff --git a/src/ui/eventframes.cpp b/src/ui/eventframes.cpp index c3f254c1..c90f3934 100644 --- a/src/ui/eventframes.cpp +++ b/src/ui/eventframes.cpp @@ -507,9 +507,9 @@ void WarpFrame::setup() { // desination warp id QFormLayout *l_form_dest_warp = new QFormLayout(); - this->spinner_dest_warp = new NoScrollSpinBox(this); - this->spinner_dest_warp->setToolTip("The warp id on the destination map."); - l_form_dest_warp->addRow("Destination Warp", this->spinner_dest_warp); + this->combo_dest_warp = new NoScrollComboBox(this); + this->combo_dest_warp->setToolTip("The warp id on the destination map."); + l_form_dest_warp->addRow("Destination Warp", this->combo_dest_warp); this->layout_contents->addLayout(l_form_dest_warp); // custom attributes @@ -529,9 +529,9 @@ void WarpFrame::connectSignals() { }); // dest id - this->spinner_dest_warp->disconnect(); - connect(this->spinner_dest_warp, QOverload::of(&QSpinBox::valueChanged), [this](int value) { - this->warp->setDestinationWarpID(value); + this->combo_dest_warp->disconnect(); + connect(this->combo_dest_warp, &QComboBox::currentTextChanged, [this](const QString &text) { + this->warp->setDestinationWarpID(text); this->warp->modify(); }); } @@ -553,7 +553,7 @@ void WarpFrame::initialize() { } // dest id - this->spinner_dest_warp->setValue(this->warp->getDestinationWarpID()); + this->combo_dest_warp->setCurrentText(this->warp->getDestinationWarpID()); } void WarpFrame::populate(Project *project) { From 4c3a508534a5e2914b5927904aaa272ee0fb1548 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 18 Oct 2022 19:52:35 -0400 Subject: [PATCH 12/13] Better type conversion custom event attributes --- include/core/events.h | 6 +- include/ui/customattributestable.h | 6 +- src/core/events.cpp | 5 +- src/editor.cpp | 35 +----- src/mainwindow.cpp | 84 ++----------- src/ui/customattributestable.cpp | 186 +++++++++++++++++++++-------- src/ui/draggablepixmapitem.cpp | 5 +- 7 files changed, 160 insertions(+), 167 deletions(-) diff --git a/include/core/events.h b/include/core/events.h index a31ca8a5..daadbde0 100644 --- a/include/core/events.h +++ b/include/core/events.h @@ -151,8 +151,8 @@ public: virtual QSet getExpectedFields() = 0; void readCustomValues(QJsonObject values); void addCustomValuesTo(OrderedJson::object *obj); - QMap getCustomValues() { return this->customValues; } - void setCustomValues(QMap newCustomValues) { this->customValues = newCustomValues; } + const QMap getCustomValues() { return this->customValues; } + void setCustomValues(const QMap newCustomValues) { this->customValues = newCustomValues; } virtual void loadPixmap(Project *project) = 0; @@ -193,7 +193,7 @@ protected: int spriteHeight = 16; bool usingSprite = false; - QMap customValues; + QMap customValues; QPixmap pixmap; DraggablePixmapItem *pixmapItem = nullptr; diff --git a/include/ui/customattributestable.h b/include/ui/customattributestable.h index bf9334d0..f17f4877 100644 --- a/include/ui/customattributestable.h +++ b/include/ui/customattributestable.h @@ -12,11 +12,15 @@ public: explicit CustomAttributesTable(Event *event, QWidget *parent = nullptr); ~CustomAttributesTable(); + static const QMap getAttributes(QTableWidget * table); + static QJsonValue pickType(QWidget * parent, bool * ok = nullptr); + static void addAttribute(QTableWidget * table, QString key, QJsonValue value, bool isNew = false); + static bool deleteSelectedAttributes(QTableWidget * table); + private: Event *event; QTableWidget *table; void resizeVertically(); - QMap getTableFields(); }; #endif // CUSTOMATTRIBUTESTABLE_H diff --git a/src/core/events.cpp b/src/core/events.cpp index c61c86b6..35b26bd3 100644 --- a/src/core/events.cpp +++ b/src/core/events.cpp @@ -38,13 +38,12 @@ void Event::setDefaultValues(Project *) { this->setElevation(3); } -// TODO: Don't assume string type void Event::readCustomValues(QJsonObject values) { this->customValues.clear(); QSet expectedFields = this->getExpectedFields(); for (QString key : values.keys()) { if (!expectedFields.contains(key)) { - this->customValues[key] = values[key].toString(); + this->customValues[key] = values[key]; } } } @@ -52,7 +51,7 @@ void Event::readCustomValues(QJsonObject values) { void Event::addCustomValuesTo(OrderedJson::object *obj) { for (QString key : this->customValues.keys()) { if (!obj->contains(key)) { - (*obj)[key] = this->customValues[key]; + (*obj)[key] = OrderedJson::fromQJsonValue(this->customValues[key]); } } } diff --git a/src/editor.cpp b/src/editor.cpp index 98000854..77380aab 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -10,6 +10,7 @@ #include "editcommands.h" #include "config.h" #include "scripting.h" +#include "customattributestable.h" #include #include #include @@ -1952,39 +1953,7 @@ void Editor::toggleBorderVisibility(bool visible, bool enableScriptCallback) void Editor::updateCustomMapHeaderValues(QTableWidget *table) { - QMap fields; - for (int row = 0; row < table->rowCount(); row++) { - QString key = ""; - QTableWidgetItem *typeItem = table->item(row, 0); - QTableWidgetItem *keyItem = table->item(row, 1); - QTableWidgetItem *valueItem = table->item(row, 2); - - if (keyItem) key = keyItem->text(); - if (key.isEmpty() || !typeItem || !valueItem) - continue; - - // Read from the table data which JSON type to save the value as - QJsonValue::Type type = static_cast(typeItem->data(Qt::UserRole).toInt()); - QJsonValue value; - switch (type) - { - case QJsonValue::String: - value = QJsonValue(valueItem->text()); - break; - case QJsonValue::Double: - value = QJsonValue(valueItem->text().toInt()); - break; - case QJsonValue::Bool: - value = QJsonValue(valueItem->checkState() == Qt::Checked); - break; - default: - // All other types will just be preserved - value = valueItem->data(Qt::UserRole).toJsonValue(); - break; - } - fields[key] = value; - } - map->customHeaders = fields; + map->customHeaders = CustomAttributesTable::getAttributes(table); emit editedMapData(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index fb4c307e..0da662b6 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -816,7 +816,7 @@ void MainWindow::displayMapProperties() { ui->tableWidget_CustomHeaderFields->blockSignals(true); ui->tableWidget_CustomHeaderFields->setRowCount(0); for (auto it = map->customHeaders.begin(); it != map->customHeaders.end(); it++) - addCustomHeaderValue(it.key(), it.value()); + CustomAttributesTable::addAttribute(ui->tableWidget_CustomHeaderFields, it.key(), it.value()); ui->tableWidget_CustomHeaderFields->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); ui->tableWidget_CustomHeaderFields->blockSignals(false); } @@ -2756,90 +2756,20 @@ void MainWindow::togglePreferenceSpecificUi() { ui->actionOpen_Project_in_Text_Editor->setEnabled(true); } -void MainWindow::addCustomHeaderValue(QString key, QJsonValue value, bool isNew) { - QTableWidgetItem * valueItem; - QJsonValue::Type type = value.type(); - switch (type) - { - case QJsonValue::String: - case QJsonValue::Double: - valueItem = new QTableWidgetItem(ParseUtil::jsonToQString(value)); - break; - case QJsonValue::Bool: - valueItem = new QTableWidgetItem(""); - valueItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked); - valueItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); - break; - default: - valueItem = new QTableWidgetItem("This value cannot be edited from this table"); - valueItem->setFlags(Qt::ItemIsSelectable); - valueItem->setData(Qt::UserRole, value); // Preserve the value for writing to the file - break; - } - - const QHash typeToName = { - {QJsonValue::Bool, "Bool"}, - {QJsonValue::Double, "Number"}, - {QJsonValue::String, "String"}, - {QJsonValue::Array, "Array"}, - {QJsonValue::Object, "Object"}, - {QJsonValue::Null, "Null"}, - {QJsonValue::Undefined, "Null"}, - }; - QTableWidgetItem * typeItem = new QTableWidgetItem(typeToName[type]); - typeItem->setFlags(Qt::ItemIsEnabled); - typeItem->setData(Qt::UserRole, type); // Record the type for writing to the file - typeItem->setTextAlignment(Qt::AlignCenter); - - int rowIndex = this->ui->tableWidget_CustomHeaderFields->rowCount(); - this->ui->tableWidget_CustomHeaderFields->insertRow(rowIndex); - this->ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 0, typeItem); - this->ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 1, new QTableWidgetItem(key)); - this->ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 2, valueItem); - - if (isNew) { - valueItem->setText(""); // Erase the "0" in new numbers - this->ui->tableWidget_CustomHeaderFields->selectRow(rowIndex); - this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields); - } -} - void MainWindow::on_pushButton_AddCustomHeaderField_clicked() { - const QMap valueTypes = { - {"String", QJsonValue(QString(""))}, - {"Number", QJsonValue(0)}, - {"Boolean", QJsonValue(false)}, - }; - bool ok; - QStringList typeNames = valueTypes.keys(); - QString selection = QInputDialog::getItem(this, "", "Choose Value Type", typeNames, typeNames.indexOf("String"), false, &ok); - if (ok) - addCustomHeaderValue("", valueTypes[selection], true); + QJsonValue value = CustomAttributesTable::pickType(this, &ok); + if (ok){ + CustomAttributesTable::addAttribute(this->ui->tableWidget_CustomHeaderFields, "", value, true); + this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields); + } } void MainWindow::on_pushButton_DeleteCustomHeaderField_clicked() { - int rowCount = this->ui->tableWidget_CustomHeaderFields->rowCount(); - if (rowCount > 0) { - QModelIndexList indexList = ui->tableWidget_CustomHeaderFields->selectionModel()->selectedIndexes(); - QList persistentIndexes; - for (QModelIndex index : indexList) { - QPersistentModelIndex persistentIndex(index); - persistentIndexes.append(persistentIndex); - } - - for (QPersistentModelIndex index : persistentIndexes) { - this->ui->tableWidget_CustomHeaderFields->removeRow(index.row()); - } - - if (this->ui->tableWidget_CustomHeaderFields->rowCount() > 0) { - this->ui->tableWidget_CustomHeaderFields->selectRow(0); - } - + if (CustomAttributesTable::deleteSelectedAttributes(this->ui->tableWidget_CustomHeaderFields)) this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields); - } } void MainWindow::on_tableWidget_CustomHeaderFields_cellChanged(int, int) diff --git a/src/ui/customattributestable.cpp b/src/ui/customattributestable.cpp index 4c41a104..83667483 100644 --- a/src/ui/customattributestable.cpp +++ b/src/ui/customattributestable.cpp @@ -1,10 +1,12 @@ #include "customattributestable.h" +#include "parseutil.h" #include #include #include #include #include #include +#include CustomAttributesTable::CustomAttributesTable(Event *event, QWidget *parent) : QFrame(parent) @@ -28,52 +30,34 @@ CustomAttributesTable::CustomAttributesTable(Event *event, QWidget *parent) : layout->addWidget(buttonsFrame); this->table = new QTableWidget(this); - this->table->setColumnCount(2); - this->table->setHorizontalHeaderLabels(QStringList({"Key", "Value"})); + this->table->setColumnCount(3); + this->table->setHorizontalHeaderLabels(QStringList({"Type", "Key", "Value"})); this->table->horizontalHeader()->setStretchLastSection(true); layout->addWidget(this->table); - QMap customValues = this->event->getCustomValues(); - for (auto it = customValues.begin(); it != customValues.end(); it++) { - int rowIndex = this->table->rowCount(); - this->table->insertRow(rowIndex); - this->table->setItem(rowIndex, 0, new QTableWidgetItem(it.key())); - this->table->setItem(rowIndex, 1, new QTableWidgetItem(it.value())); - } + QMap customValues = this->event->getCustomValues(); + for (auto it = customValues.begin(); it != customValues.end(); it++) + CustomAttributesTable::addAttribute(this->table, it.key(), it.value()); connect(addButton, &QPushButton::clicked, [=]() { - int rowIndex = this->table->rowCount(); - this->table->insertRow(rowIndex); - this->table->selectRow(rowIndex); - this->event->setCustomValues(this->getTableFields()); - this->resizeVertically(); + bool ok; + QJsonValue value = CustomAttributesTable::pickType(this, &ok); + if (ok){ + CustomAttributesTable::addAttribute(this->table, "", value, true); + this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table)); + this->resizeVertically(); + } }); connect(deleteButton, &QPushButton::clicked, [=]() { - int rowCount = this->table->rowCount(); - if (rowCount > 0) { - QModelIndexList indexList = this->table->selectionModel()->selectedIndexes(); - QList persistentIndexes; - for (QModelIndex index : indexList) { - QPersistentModelIndex persistentIndex(index); - persistentIndexes.append(persistentIndex); - } - - for (QPersistentModelIndex index : persistentIndexes) { - this->table->removeRow(index.row()); - } - - if (this->table->rowCount() > 0) { - this->table->selectRow(0); - } - - this->event->setCustomValues(this->getTableFields()); + if (CustomAttributesTable::deleteSelectedAttributes(this->table)) { + this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table)); this->resizeVertically(); } }); connect(this->table, &QTableWidget::cellChanged, [=]() { - this->event->setCustomValues(this->getTableFields()); + this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table)); }); this->resizeVertically(); @@ -83,20 +67,6 @@ CustomAttributesTable::~CustomAttributesTable() { } -QMap CustomAttributesTable::getTableFields() { - QMap fields; - for (int row = 0; row < table->rowCount(); row++) { - QString keyStr = ""; - QString valueStr = ""; - QTableWidgetItem *key = table->item(row, 0); - QTableWidgetItem *value = table->item(row, 1); - if (key) keyStr = key->text(); - if (value) valueStr = value->text(); - fields[keyStr] = valueStr; - } - return fields; -} - void CustomAttributesTable::resizeVertically() { int horizontalHeaderHeight = this->table->horizontalHeader()->height(); int rowHeight = 0; @@ -112,3 +82,125 @@ void CustomAttributesTable::resizeVertically() { this->table->setMinimumHeight(totalHeight); this->table->setMaximumHeight(totalHeight); } + +const QMap CustomAttributesTable::getAttributes(QTableWidget * table) { + QMap fields; + if (!table) return fields; + + for (int row = 0; row < table->rowCount(); row++) { + QString key = ""; + QTableWidgetItem *typeItem = table->item(row, 0); + QTableWidgetItem *keyItem = table->item(row, 1); + QTableWidgetItem *valueItem = table->item(row, 2); + + if (keyItem) key = keyItem->text(); + if (key.isEmpty() || !typeItem || !valueItem) + continue; + + // Read from the table data which JSON type to save the value as + QJsonValue::Type type = static_cast(typeItem->data(Qt::UserRole).toInt()); + QJsonValue value; + switch (type) + { + case QJsonValue::String: + value = QJsonValue(valueItem->text()); + break; + case QJsonValue::Double: + value = QJsonValue(valueItem->text().toInt()); + break; + case QJsonValue::Bool: + value = QJsonValue(valueItem->checkState() == Qt::Checked); + break; + default: + // All other types will just be preserved + value = valueItem->data(Qt::UserRole).toJsonValue(); + break; + } + fields[key] = value; + } + return fields; +} + +QJsonValue CustomAttributesTable::pickType(QWidget * parent, bool * ok) { + const QMap valueTypes = { + {"String", QJsonValue(QString(""))}, + {"Number", QJsonValue(0)}, + {"Boolean", QJsonValue(false)}, + }; + QStringList typeNames = valueTypes.keys(); + QString selection = QInputDialog::getItem(parent, "", "Choose Value Type", typeNames, typeNames.indexOf("String"), false, ok); + return valueTypes.value(selection); +} + +void CustomAttributesTable::addAttribute(QTableWidget * table, QString key, QJsonValue value, bool isNew) { + if (!table) return; + QTableWidgetItem * valueItem; + QJsonValue::Type type = value.type(); + switch (type) + { + case QJsonValue::String: + case QJsonValue::Double: + valueItem = new QTableWidgetItem(ParseUtil::jsonToQString(value)); + break; + case QJsonValue::Bool: + valueItem = new QTableWidgetItem(""); + valueItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked); + valueItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + break; + default: + valueItem = new QTableWidgetItem("This value cannot be edited from this table"); + valueItem->setFlags(Qt::ItemIsSelectable); + valueItem->setData(Qt::UserRole, value); // Preserve the value for writing to the file + break; + } + + const QHash typeToName = { + {QJsonValue::Bool, "Bool"}, + {QJsonValue::Double, "Number"}, + {QJsonValue::String, "String"}, + {QJsonValue::Array, "Array"}, + {QJsonValue::Object, "Object"}, + {QJsonValue::Null, "Null"}, + {QJsonValue::Undefined, "Null"}, + }; + QTableWidgetItem * typeItem = new QTableWidgetItem(typeToName[type]); + typeItem->setFlags(Qt::ItemIsEnabled); + typeItem->setData(Qt::UserRole, type); // Record the type for writing to the file + typeItem->setTextAlignment(Qt::AlignCenter); + + int rowIndex = table->rowCount(); + table->insertRow(rowIndex); + table->setItem(rowIndex, 0, typeItem); + table->setItem(rowIndex, 1, new QTableWidgetItem(key)); + table->setItem(rowIndex, 2, valueItem); + + if (isNew) { + valueItem->setText(""); // Erase the "0" in new numbers + table->selectRow(rowIndex); + } +} + +bool CustomAttributesTable::deleteSelectedAttributes(QTableWidget * table) { + if (!table) + return false; + + int rowCount = table->rowCount(); + if (rowCount <= 0) + return false; + + QModelIndexList indexList = table->selectionModel()->selectedIndexes(); + QList persistentIndexes; + for (QModelIndex index : indexList) { + QPersistentModelIndex persistentIndex(index); + persistentIndexes.append(persistentIndex); + } + + for (QPersistentModelIndex index : persistentIndexes) { + table->removeRow(index.row()); + } + + if (table->rowCount() > 0) { + table->selectRow(0); + } + return true; +} diff --git a/src/ui/draggablepixmapitem.cpp b/src/ui/draggablepixmapitem.cpp index d06c9786..9e7ab855 100644 --- a/src/ui/draggablepixmapitem.cpp +++ b/src/ui/draggablepixmapitem.cpp @@ -85,9 +85,8 @@ void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) { if (eventType == Event::Type::Warp) { WarpEvent *warp = dynamic_cast(this->event); QString destMap = warp->getDestinationMap(); - bool ok; - int warpId = ParseUtil::gameStringToInt(warp->getDestinationWarpID(), &ok); - if (ok) emit editor->warpEventDoubleClicked(destMap, warpId, Event::Group::Warp); + int warpId = ParseUtil::gameStringToInt(warp->getDestinationWarpID()); + emit editor->warpEventDoubleClicked(destMap, warpId, Event::Group::Warp); } else if (eventType == Event::Type::CloneObject) { CloneObjectEvent *clone = dynamic_cast(this->event); From d2d28f9a5a6dffc80c66413340abc1fc9109b5b6 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 18 Oct 2022 22:44:14 -0400 Subject: [PATCH 13/13] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4589e78b..8d4945b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d ### Changed - Overhauled the region map editor, adding support for tilemaps, and significant customization. Also now supports pokefirered. +- The Custom Attributes table for map headers and events now supports types other than strings. - If an object event is inanimate, it will always render using its first frame. - Unused metatile attribute bits are preserved instead of being cleared. - The wild encounter editor is automatically disabled if the encounter JSON data cannot be read @@ -35,6 +36,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d - Palette editor ui is updated a bit to allow hex and rgb value input. - The metatile behavior is now displayed in the bottom bar mouseover text. - Removed some unnecessary error logs from the scripting API and added new useful ones. +- If any JSON data is the incorrect type Porymap will now attempt to convert it. ### Fixed - Fix cursor tile outline not updating at the end of a dragged selection.