diff --git a/docs/_sources/manual/project-files.rst.txt b/docs/_sources/manual/project-files.rst.txt index e9e0e652..bbc71d70 100644 --- a/docs/_sources/manual/project-files.rst.txt +++ b/docs/_sources/manual/project-files.rst.txt @@ -47,6 +47,7 @@ The filepath that Porymap expects for each file can be overridden on the ``Files src/data/object_events/object_event_graphics.h, yes, no, ``data_obj_event_gfx``, "to locate object event sprites using data from ``data_obj_event_pic_tables``" src/data/graphics/pokemon.h, yes, no, ``data_pokemon_gfx``, "if ``symbol_pokemon_icon_table`` is read this file will be searched for filepaths to species icon" src/data/region_map/region_map_sections.json, yes, yes, ``json_region_map_entries``, "for populating the locations list and for region map data" + src/data/region_map/regions.json, yes, yes, ``json_region_entries``, "For populating the regions list and for region map data" src/data/region_map/porymap_config.json, yes, yes, ``json_region_porymap_cfg``, "Porymap's config file for the region map editor" include/constants/global.h, yes, no, ``constants_global``, "to evaluate ``define_obj_event_count``" include/constants/items.h, yes, no, ``constants_items``, "to find ``regex_items`` names" diff --git a/docs/manual/project-files.html b/docs/manual/project-files.html index d220769e..d326e86d 100644 --- a/docs/manual/project-files.html +++ b/docs/manual/project-files.html @@ -596,145 +596,151 @@ to a file, it probably is not a good idea to edit yourself unless otherwise note

json_region_map_entries

for populating the locations list and for region map data

-

src/data/region_map/porymap_config.json

+

src/data/region_map/regions.json

+

yes

+

yes

+

json_region_entries

+

For populating the regions list and for region map data

+ +

src/data/region_map/porymap_config.json

yes

yes

json_region_porymap_cfg

Porymap’s config file for the region map editor

-

include/constants/global.h

+

include/constants/global.h

yes

no

constants_global

to evaluate define_obj_event_count

-

include/constants/items.h

+

include/constants/items.h

yes

no

constants_items

to find regex_items names

-

include/constants/flags.h

+

include/constants/flags.h

yes

no

constants_flags

to find regex_flags names

-

include/constants/vars.h

+

include/constants/vars.h

yes

no

constants_vars

to find regex_vars names

-

include/constants/weather.h

+

include/constants/weather.h

yes

no

constants_weather

to find regex_weather names

-

include/constants/songs.h

+

include/constants/songs.h

yes

no

constants_songs

to find regex_music names

-

include/constants/pokemon.h

+

include/constants/pokemon.h

yes

no

constants_pokemon

to evaluate define_min_level and define_max_level

-

include/constants/map_types.h

+

include/constants/map_types.h

yes

no

constants_map_types

to find regex_map_types and regex_battle_scenes names

-

include/constants/trainer_types.h

+

include/constants/trainer_types.h

yes

no

constants_trainer_types

to find regex_trainer_types names

-

include/constants/secret_bases.h

+

include/constants/secret_bases.h

yes

no

constants_secret_bases

to find regex_secret_bases names

-

include/constants/event_object_movement.h

+

include/constants/event_object_movement.h

yes

no

constants_obj_event_movement

to find regex_movement_types names

-

include/constants/event_objects.h

+

include/constants/event_objects.h

yes

no

constants_obj_events

to evaluate regex_obj_event_gfx constants

-

include/constants/event_bg.h

+

include/constants/event_bg.h

yes

no

constants_event_bg

to find regex_sign_facing_directions names

-

include/constants/metatile_labels.h

+

include/constants/metatile_labels.h

yes

yes

constants_metatile_labels

to read/write metatile labels using define_metatile_label_prefix

-

include/constants/metatile_behaviors.h

+

include/constants/metatile_behaviors.h

yes

no

constants_metatile_behaviors

to evaluate regex_behaviors constants

-

include/constants/species.h

+

include/constants/species.h

yes

no

constants_species

to find names using define_species_prefix

-

include/global.fieldmap.h

+

include/global.fieldmap.h

yes

no

global_fieldmap

to evaluate map and tileset data masks, and to read regex_encounter_types / regex_terrain_types

-

include/fieldmap.h

+

include/fieldmap.h

yes

no

constants_fieldmap

to evaluate a variety of tileset and map constants

-

src/fieldmap.c

+

src/fieldmap.c

yes

no

fieldmap

to read symbol_attribute_table

-

src/event_object_movement.c

+

src/event_object_movement.c

yes

no

initial_facing_table

to read symbol_facing_directions

-

src/wild_encounter.c

+

src/wild_encounter.c

yes

no

wild_encounter

to evaluate define_max_encounter_rate

-

src/pokemon_icon.c

+

src/pokemon_icon.c

yes

no

pokemon_icon_table

to read symbol_pokemon_icon_table

-

graphics/pokemon/

+

graphics/pokemon/

yes

no

pokemon_gfx

diff --git a/docsrc/manual/project-files.rst b/docsrc/manual/project-files.rst index e9e0e652..bbc71d70 100644 --- a/docsrc/manual/project-files.rst +++ b/docsrc/manual/project-files.rst @@ -47,6 +47,7 @@ The filepath that Porymap expects for each file can be overridden on the ``Files src/data/object_events/object_event_graphics.h, yes, no, ``data_obj_event_gfx``, "to locate object event sprites using data from ``data_obj_event_pic_tables``" src/data/graphics/pokemon.h, yes, no, ``data_pokemon_gfx``, "if ``symbol_pokemon_icon_table`` is read this file will be searched for filepaths to species icon" src/data/region_map/region_map_sections.json, yes, yes, ``json_region_map_entries``, "for populating the locations list and for region map data" + src/data/region_map/regions.json, yes, yes, ``json_region_entries``, "For populating the regions list and for region map data" src/data/region_map/porymap_config.json, yes, yes, ``json_region_porymap_cfg``, "Porymap's config file for the region map editor" include/constants/global.h, yes, no, ``constants_global``, "to evaluate ``define_obj_event_count``" include/constants/items.h, yes, no, ``constants_items``, "to find ``regex_items`` names" diff --git a/forms/mapheaderform.ui b/forms/mapheaderform.ui index d4fc36f3..3349288a 100644 --- a/forms/mapheaderform.ui +++ b/forms/mapheaderform.ui @@ -40,14 +40,14 @@ - + Location - + <html><head/><body><p>The section of the region map which the map is grouped under. This also determines the name of the map that is displayed when the player enters it.</p></body></html> @@ -60,14 +60,14 @@ - + Requires Flash - + <html><head/><body><p>If checked, the player will need to use Flash to see fully on this map.</p></body></html> @@ -77,14 +77,14 @@ - + Weather - + <html><head/><body><p>The default weather on this map.</p></body></html> @@ -97,14 +97,14 @@ - + Type - + <html><head/><body><p>The map type is a general attribute, which is used for many different things. For example, underground type maps will have a special transition effect when the player enters/exits the map.</p></body></html> @@ -117,14 +117,14 @@ - + Battle Scene - + <html><head/><body><p>This field is used to help determine what graphics to use in the background of battles on this map.</p></body></html> @@ -137,14 +137,14 @@ - + Show Location Name - + <html><head/><body><p>If checked, a map name popup will appear when the player enters this map. The name that appears on this popup depends on the Location field.</p></body></html> @@ -154,14 +154,14 @@ - + Allow Running - + <html><head/><body><p>If checked, the player will be allowed to run on this map.</p></body></html> @@ -171,14 +171,14 @@ - + Allow Biking - + <html><head/><body><p>If checked, the player will be allowed to get on their bike on this map.</p></body></html> @@ -188,14 +188,14 @@ - + Allow Dig & Escape Rope - + <html><head/><body><p>If checked, the player will be allowed to use Dig or Escape Rope on this map.</p></body></html> @@ -205,34 +205,44 @@ - + Floor Number - + <html><head/><body><p>Floor number to be used for maps with elevators.</p></body></html> - + Location Name - + <html><head/><body><p>The name that will be displayed in-game for this Location. This name will be shared with any other map that has the same Location.</p></body></html> + + + + Region + + + + + + diff --git a/include/config.h b/include/config.h index ae1d1d2c..ed667b87 100644 --- a/include/config.h +++ b/include/config.h @@ -225,6 +225,9 @@ enum ProjectIdentifier { define_map_empty, define_map_section_prefix, define_map_section_empty, + define_region_prefix, + define_region_empty, + define_region_count, define_species_prefix, define_species_empty, regex_behaviors, @@ -259,6 +262,7 @@ enum ProjectFilePath { json_wild_encounters, json_heal_locations, json_region_map_entries, + json_region_entries, json_region_porymap_cfg, tilesets_headers, tilesets_graphics, diff --git a/include/core/mapheader.h b/include/core/mapheader.h index 2058280a..7c18b734 100644 --- a/include/core/mapheader.h +++ b/include/core/mapheader.h @@ -14,6 +14,7 @@ public: bool operator==(const MapHeader& other) const { return m_song == other.m_song && m_location == other.m_location + && m_region == other.m_region && m_requiresFlash == other.m_requiresFlash && m_weather == other.m_weather && m_type == other.m_type @@ -30,6 +31,8 @@ public: void setSong(const QString &song); void setLocation(const QString &location); + void setRegion(const QString ®ion); + void setUsesMultiRegion(bool usesMultiRegion); void setRequiresFlash(bool requiresFlash); void setWeather(const QString &weather); void setType(const QString &type); @@ -42,6 +45,8 @@ public: QString song() const { return m_song; } QString location() const { return m_location; } + QString region() const { return m_region; } + bool usesMultiRegion() const { return m_usesMultiRegion; } bool requiresFlash() const { return m_requiresFlash; } QString weather() const { return m_weather; } QString type() const { return m_type; } @@ -55,6 +60,8 @@ public: signals: void songChanged(QString); void locationChanged(QString); + void regionChanged(QString); + void usesMultiRegionChanged(bool); void requiresFlashChanged(bool); void weatherChanged(QString); void typeChanged(QString); @@ -69,6 +76,8 @@ signals: private: QString m_song; QString m_location; + QString m_region; + bool m_usesMultiRegion = false; bool m_requiresFlash = false; QString m_weather; QString m_type; diff --git a/include/project.h b/include/project.h index c377362b..89d72dd3 100644 --- a/include/project.h +++ b/include/project.h @@ -52,6 +52,11 @@ public: QStringList bgEventFacingDirections; QStringList trainerTypes; QStringList globalScriptLabels; + QStringList mapSectionIdNamesSaveOrder; + QStringList mapSectionIdNames; + QStringList regionIdNamesSaveOrder; + QStringList regionIdNames; + bool usingMultiRegion; QMap encounterTypeToName; QMap terrainTypeToName; QMap> metatileLabelsMap; @@ -187,6 +192,7 @@ public: bool readTilesetLabels(); bool readTilesetMetatileLabels(); bool readRegionMapSections(); + bool readRegionEntries(); bool readItemNames(); bool readFlagNames(); bool readVarNames(); @@ -273,6 +279,7 @@ public: static int getNumPalettesTotal() { return num_pals_total; } static int getNumPalettesSecondary() { return getNumPalettesTotal() - getNumPalettesPrimary(); } static QString getEmptyMapsecName(); + static QString getEmptyRegionName(); static QString getMapGroupPrefix(); private: @@ -289,8 +296,6 @@ private: QStringList orderedLayoutIdsMaster; QHash mapLayouts; QHash mapLayoutsMaster; - QStringList mapSectionIdNamesSaveOrder; - QStringList mapSectionIdNames; // Fields for preserving top-level JSON data that Porymap isn't expecting. QJsonObject customLayoutsData; @@ -339,6 +344,14 @@ private: }; QHash locationData; + // The extra data that can be associated with each REGION name. + struct RegionData + { + QString displayName; + QString displayText; + }; + QHash regionData; + QJsonDocument readMapJson(const QString &mapName, QString *error = nullptr); void setNewLayoutBlockdata(Layout *layout); @@ -384,6 +397,7 @@ signals: void mapSectionAdded(const QString &idName); void mapSectionDisplayNameChanged(const QString &idName, const QString &displayName); void mapSectionIdNamesChanged(const QStringList &idNames); + void regionIdNamesChanged(const QStringList &idNames); void eventScriptLabelsRead(); }; diff --git a/include/ui/mapheaderform.h b/include/ui/mapheaderform.h index fb4f7aa9..da2a9a87 100644 --- a/include/ui/mapheaderform.h +++ b/include/ui/mapheaderform.h @@ -35,6 +35,7 @@ public: void setSong(const QString &song); void setLocation(const QString &location); + void setRegion(const QString ®ion); void setLocationName(const QString &locationName); void setRequiresFlash(bool requiresFlash); void setWeather(const QString &weather); @@ -48,6 +49,7 @@ public: QString song() const; QString location() const; + QString region() const; QString locationName() const; bool requiresFlash() const; QString weather() const; @@ -68,10 +70,12 @@ private: void setText(NoScrollComboBox *combo, const QString &text) const; void setText(QLineEdit *lineEdit, const QString &text) const; void setLocations(const QStringList &locations); + void setRegions(const QStringList ®ions); void updateLocationName(); void onSongUpdated(const QString &song); void onLocationChanged(const QString &location); + void onRegionChanged(const QString ®ion); void onLocationNameChanged(const QString &locationName); void onWeatherChanged(const QString &weather); void onTypeChanged(const QString &type); diff --git a/src/config.cpp b/src/config.cpp index b2c2d9dc..aca22dbb 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -114,6 +114,9 @@ const QMap> ProjectConfig::defaultIde {ProjectIdentifier::define_map_empty, {"define_map_empty", "MAP_UNDEFINED"}}, {ProjectIdentifier::define_map_section_prefix, {"define_map_section_prefix", "MAPSEC_"}}, {ProjectIdentifier::define_map_section_empty, {"define_map_section_empty", "NONE"}}, + {ProjectIdentifier::define_region_prefix, {"define_region_prefix", "REGION_"}}, + {ProjectIdentifier::define_region_empty, {"define_region_empty", "NONE"}}, + {ProjectIdentifier::define_region_count, {"define_region_count", "REGIONS_COUNT"}}, {ProjectIdentifier::define_species_prefix, {"define_species_prefix", "SPECIES_"}}, {ProjectIdentifier::define_species_empty, {"define_species_empty", "NONE"}}, // Regex @@ -150,6 +153,7 @@ const QMap> ProjectConfig::defaultPaths {ProjectFilePath::json_wild_encounters, { "json_wild_encounters", "src/data/wild_encounters.json"}}, {ProjectFilePath::json_heal_locations, { "json_heal_locations", "src/data/heal_locations.json"}}, {ProjectFilePath::json_region_map_entries, { "json_region_map_entries", "src/data/region_map/region_map_sections.json"}}, + {ProjectFilePath::json_region_entries, { "json_region_entries", "src/data/region_map/regions.json"}}, {ProjectFilePath::json_region_porymap_cfg, { "json_region_porymap_cfg", "src/data/region_map/porymap_config.json"}}, {ProjectFilePath::tilesets_headers, { "tilesets_headers", "src/data/tilesets/headers.h"}}, {ProjectFilePath::tilesets_graphics, { "tilesets_graphics", "src/data/tilesets/graphics.h"}}, diff --git a/src/core/mapheader.cpp b/src/core/mapheader.cpp index 689a52dc..1fc18aba 100644 --- a/src/core/mapheader.cpp +++ b/src/core/mapheader.cpp @@ -3,6 +3,7 @@ MapHeader::MapHeader(const MapHeader& other) : MapHeader() { m_song = other.m_song; m_location = other.m_location; + m_region = other.m_region; m_requiresFlash = other.m_requiresFlash; m_weather = other.m_weather; m_type = other.m_type; @@ -20,6 +21,7 @@ MapHeader &MapHeader::operator=(const MapHeader &other) { // repeatedly (but for now at least that's not a big issue). setSong(other.m_song); setLocation(other.m_location); + setRegion((other.m_region)); setRequiresFlash(other.m_requiresFlash); setWeather(other.m_weather); setType(other.m_type); @@ -48,6 +50,22 @@ void MapHeader::setLocation(const QString &location) { emit modified(); } +void MapHeader::setRegion(const QString ®ion) { + if (m_region == region) + return; + m_region = region; + emit regionChanged(m_region); + emit modified(); +} + +void MapHeader::setUsesMultiRegion(bool usesMultiRegion) { + if (m_usesMultiRegion == usesMultiRegion) + return; + m_usesMultiRegion = usesMultiRegion; + emit usesMultiRegionChanged(m_usesMultiRegion); + emit modified(); +} + void MapHeader::setRequiresFlash(bool requiresFlash) { if (m_requiresFlash == requiresFlash) return; diff --git a/src/project.cpp b/src/project.cpp index 6fd27b17..c4df1b09 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -218,7 +218,7 @@ bool Project::load() { && readSongNames() && readMapGroups() && readHealLocations(); - + this->usingMultiRegion = readRegionEntries(); if (success) { // No need to do this if something failed to load. // (and in fact we shouldn't, because they contain @@ -445,6 +445,14 @@ bool Project::loadMapData(Map* map) { map->header()->setType(ParseUtil::jsonToQString(mapObj.take("map_type"))); map->header()->setShowsLocationName(ParseUtil::jsonToBool(mapObj.take("show_map_name"))); map->header()->setBattleScene(ParseUtil::jsonToQString(mapObj.take("battle_scene"))); + + if (this->usingMultiRegion) { + if (mapObj.contains("region")) { + map->header()->setRegion(ParseUtil::jsonToQString(mapObj.take("region"))); + } else { + map->header()->setRegion(getEmptyRegionName()); + } + } if (projectConfig.mapAllowFlagsEnabled) { map->header()->setAllowsBiking(ParseUtil::jsonToBool(mapObj.take("allow_cycling"))); @@ -1369,6 +1377,11 @@ bool Project::saveMap(Map *map, bool skipLayout) { mapObj["layout"] = map->layoutId(); mapObj["music"] = map->header()->song(); mapObj["region_map_section"] = map->header()->location(); + if (this->usingMultiRegion) { + if (map->header()->region() != getEmptyRegionName()) { + mapObj["region"] = map->header()->region(); + } + } mapObj["requires_flash"] = map->header()->requiresFlash(); mapObj["weather"] = map->header()->weather(); mapObj["map_type"] = map->header()->type(); @@ -2169,6 +2182,8 @@ bool Project::isIdentifierUnique(const QString &identifier) const { return false; if (this->mapSectionIdNames.contains(identifier)) return false; + if (this->regionIdNames.contains(identifier)) + return false; if (this->tilesetLabelsOrdered.contains(identifier)) return false; if (this->mapLayouts.contains(identifier)) @@ -2227,6 +2242,8 @@ void Project::initNewMapSettings() { this->newMapSettings.header.setSong(this->defaultSong); this->newMapSettings.header.setLocation(this->mapSectionIdNames.value(0, "0")); + this->newMapSettings.header.setRegion(this->regionIdNames.value(0, "0")); + this->newMapSettings.header.setUsesMultiRegion(this->usingMultiRegion); this->newMapSettings.header.setRequiresFlash(false); this->newMapSettings.header.setWeather(this->weatherNames.value(0, "0")); this->newMapSettings.header.setType(this->mapTypes.value(0, "0")); @@ -2651,6 +2668,71 @@ bool Project::readRegionMapSections() { return true; } +bool Project::readRegionEntries() +{ + this->regionData.clear(); + this->regionIdNames.clear(); + this->regionIdNamesSaveOrder.clear(); + + const QString defaultName = getEmptyRegionName(); + const QString requiredPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_region_prefix); + + QJsonDocument doc; + const QString filepath = projectConfig.getFilePath(ProjectFilePath::json_region_entries); + QString error; + if (!parser.tryParseJsonFile(&doc, filepath, &error)) { + logWarn(QString("Failed to read region entries from '%1': %2").arg(filepath).arg(error)); + return false; + } + watchFile(filepath); + + // Make sure the default name is present in the list. + if (!this->regionIdNames.contains(defaultName)) { + this->regionIdNames.append(defaultName); + } + + QJsonObject regionsGlobalObj = doc.object(); + QJsonArray regions = regionsGlobalObj.take("regions").toArray(); + logInfo(QString("[REGION] Loading %1 regions from %2").arg(regions.size()).arg(filepath)); + for (int i = 0; i < regions.size(); i++) { + QJsonObject regionObj = regions.at(i).toObject(); + + // For each region, "id" is the only required field. This is the field we use to display the region names in various drop-downs. + QString idField = "id"; + + const QString idName = ParseUtil::jsonToQString(regionObj.take(idField)); + if (!idName.startsWith(requiredPrefix)) { + logWarn(QString("Ignoring data for region '%1' in '%2'. IDs must start with the prefix '%3'").arg(idName).arg(filepath).arg(requiredPrefix)); + continue; + } + logInfo(QString("[REGION] Region ID: %1").arg(idName)); + this->regionIdNames.append(idName); + this->regionIdNamesSaveOrder.append(idName); + + // Regions in the json file have additional data for generating region name strings. + RegionData region; + if (regionObj.contains("name")) { + region.displayName = ParseUtil::jsonToQString(regionObj.take("name")); + } else { + QString suffix = idName.mid(requiredPrefix.length()); + QString normalizedName = suffix.toLower(); + if (!normalizedName.isEmpty()) { + normalizedName[0] = normalizedName[0].toUpper(); + } + region.displayName = normalizedName; + } + if (regionObj.contains("text")) { + region.displayText = ParseUtil::jsonToQString(regionObj.take("text")); + } else { + region.displayText = idName.mid(requiredPrefix.length()); + } + this->regionData.insert(idName, region); + } + Util::numericalModeSort(this->regionIdNames); + + return true; +} + void Project::setRegionMapEntries(const QHash &entries) { for (auto it = this->locationData.keyBegin(); it != this->locationData.keyEnd(); it++) { this->locationData[*it].map = entries.value(*it); @@ -2672,6 +2754,10 @@ QString Project::getEmptyMapsecName() { return projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix) + projectConfig.getIdentifier(ProjectIdentifier::define_map_section_empty); } +QString Project::getEmptyRegionName() { + return projectConfig.getIdentifier(ProjectIdentifier::define_region_prefix) + projectConfig.getIdentifier(ProjectIdentifier::define_region_empty); +} + QString Project::getMapGroupPrefix() { // We could expose this to users, but it's never enforced so it probably won't affect anyone. return QStringLiteral("gMapGroup_"); diff --git a/src/ui/mapheaderform.cpp b/src/ui/mapheaderform.cpp index 921aec82..c6f2fb44 100644 --- a/src/ui/mapheaderform.cpp +++ b/src/ui/mapheaderform.cpp @@ -16,6 +16,7 @@ MapHeaderForm::MapHeaderForm(QWidget *parent) connect(ui->comboBox_Song, &QComboBox::currentTextChanged, this, &MapHeaderForm::onSongUpdated); connect(ui->comboBox_Location, &QComboBox::currentTextChanged, this, &MapHeaderForm::onLocationChanged); + connect(ui->comboBox_Region, &QComboBox::currentTextChanged, this, &MapHeaderForm::onRegionChanged); connect(ui->comboBox_Weather, &QComboBox::currentTextChanged, this, &MapHeaderForm::onWeatherChanged); connect(ui->comboBox_Type, &QComboBox::currentTextChanged, this, &MapHeaderForm::onTypeChanged); connect(ui->comboBox_BattleScene, &QComboBox::currentTextChanged, this, &MapHeaderForm::onBattleSceneChanged); @@ -69,6 +70,10 @@ void MapHeaderForm::setProject(Project * project, bool allowChanges) { ui->comboBox_Location->clear(); ui->comboBox_Location->addItems(m_project->locationNames()); + const QSignalBlocker b_Regions(ui->comboBox_Region); + ui->comboBox_Region->clear(); + ui->comboBox_Region->addItems(m_project->regionIdNames); + // Hide config-specific settings bool hasFlags = projectConfig.mapAllowFlagsEnabled; @@ -83,8 +88,13 @@ void MapHeaderForm::setProject(Project * project, bool allowChanges) { ui->spinBox_FloorNumber->setVisible(floorNumEnabled); ui->label_FloorNumber->setVisible(floorNumEnabled); + // Enable/disable region combo box + ui->label_Region->setVisible(m_project->usingMultiRegion); + ui->comboBox_Region->setVisible(m_project->usingMultiRegion); + // If the project changes any of the displayed data, update it accordingly. connect(m_project, &Project::mapSectionIdNamesChanged, this, &MapHeaderForm::setLocations); + connect(m_project, &Project::regionIdNamesChanged, this, &MapHeaderForm::setRegions); connect(m_project, &Project::mapSectionDisplayNameChanged, this, &MapHeaderForm::updateLocationName); } @@ -96,6 +106,14 @@ void MapHeaderForm::setLocations(const QStringList &locations) { ui->comboBox_Location->setTextItem(before); } +void MapHeaderForm::setRegions(const QStringList ®ions) { + const QSignalBlocker b(ui->comboBox_Region); + const QString before = ui->comboBox_Region->currentText(); + ui->comboBox_Region->clear(); + ui->comboBox_Region->addItems(regions); + ui->comboBox_Region->setTextItem(before); +} + // Assign a MapHeader that the form will keep in sync with the UI. void MapHeaderForm::setHeader(MapHeader *header) { if (m_header == header) @@ -114,6 +132,7 @@ void MapHeaderForm::setHeader(MapHeader *header) { // If the MapHeader is changed externally (for example, with the scripting API) update the UI accordingly connect(m_header, &MapHeader::songChanged, this, &MapHeaderForm::setSong); connect(m_header, &MapHeader::locationChanged, this, &MapHeaderForm::setLocation); + connect(m_header, &MapHeader::regionChanged, this, &MapHeaderForm::setRegion); connect(m_header, &MapHeader::requiresFlashChanged, this, &MapHeaderForm::setRequiresFlash); connect(m_header, &MapHeader::weatherChanged, this, &MapHeaderForm::setWeather); connect(m_header, &MapHeader::typeChanged, this, &MapHeaderForm::setType); @@ -136,6 +155,7 @@ void MapHeaderForm::clear() { void MapHeaderForm::setHeaderData(const MapHeader &header) { setSong(header.song()); setLocation(header.location()); + setRegion(header.region()); setRequiresFlash(header.requiresFlash()); setWeather(header.weather()); setType(header.type()); @@ -156,6 +176,7 @@ MapHeader MapHeaderForm::headerData() const { MapHeader header; header.setSong(song()); header.setLocation(location()); + header.setRegion(region()); header.setRequiresFlash(requiresFlash()); header.setWeather(weather()); header.setType(type()); @@ -175,6 +196,7 @@ void MapHeaderForm::updateLocationName() { // Set data in UI void MapHeaderForm::setSong(const QString &song) { setText(ui->comboBox_Song, song); } void MapHeaderForm::setLocation(const QString &location) { setText(ui->comboBox_Location, location); } +void MapHeaderForm::setRegion(const QString ®ion) { setText(ui->comboBox_Region, region); } void MapHeaderForm::setLocationName(const QString &locationName) { setText(ui->lineEdit_LocationName, locationName); } void MapHeaderForm::setRequiresFlash(bool requiresFlash) { ui->checkBox_RequiresFlash->setChecked(requiresFlash); } void MapHeaderForm::setWeather(const QString &weather) { setText(ui->comboBox_Weather, weather); } @@ -199,6 +221,7 @@ void MapHeaderForm::setText(QLineEdit *lineEdit, const QString &text) const { // Read data from UI QString MapHeaderForm::song() const { return ui->comboBox_Song->currentText(); } QString MapHeaderForm::location() const { return ui->comboBox_Location->currentText(); } +QString MapHeaderForm::region() const { return ui->comboBox_Region->currentText(); } QString MapHeaderForm::locationName() const { return ui->lineEdit_LocationName->text(); } bool MapHeaderForm::requiresFlash() const { return ui->checkBox_RequiresFlash->isChecked(); } QString MapHeaderForm::weather() const { return ui->comboBox_Weather->currentText(); } @@ -225,6 +248,7 @@ void MapHeaderForm::onLocationChanged(const QString &location) { if (m_header) m_header->setLocation(location); updateLocationName(); } +void MapHeaderForm::onRegionChanged(const QString ®ion) { if (m_header) m_header->setRegion(region); } void MapHeaderForm::onLocationNameChanged(const QString &locationName) { if (m_project && m_allowProjectChanges) { // The location name is actually part of the project, not the map header.