diff --git a/docsrc/manual/project-files.rst b/docsrc/manual/project-files.rst index 20849ba3..1da0fbc6 100644 --- a/docsrc/manual/project-files.rst +++ b/docsrc/manual/project-files.rst @@ -120,6 +120,7 @@ In addition to these files, there are some specific symbol and macro names that ``define_map_section_prefix``, ``MAPSEC_``, expected prefix for location macro names ``define_map_section_empty``, ``NONE``, macro name after prefix for empty region map sections ``define_map_section_count``, ``COUNT``, macro name after prefix for total number of region map sections + ``define_species_prefix``, ``SPECIES_``, expected prefix for species macro names ``regex_behaviors``, ``\bMB_``, regex to find metatile behavior macro names ``regex_obj_event_gfx``, ``\bOBJ_EVENT_GFX_``, regex to find Object Event graphics ID macro names ``regex_items``, ``\bITEM_(?!(B_)?USE_)``, regex to find item macro names @@ -134,4 +135,3 @@ In addition to these files, there are some specific symbol and macro names that ``regex_sign_facing_directions``, ``\bBG_EVENT_PLAYER_FACING_``, regex to find sign facing direction macro names ``regex_trainer_types``, ``\bTRAINER_TYPE_``, regex to find trainer type macro names ``regex_music``, ``\b(SE|MUS)_``, regex to find music macro names - ``regex_species``, ``\bSPECIES_``, regex to find species macro names diff --git a/forms/wildmonchart.ui b/forms/wildmonchart.ui index 035272c2..5542afc3 100644 --- a/forms/wildmonchart.ui +++ b/forms/wildmonchart.ui @@ -6,8 +6,8 @@ 0 0 - 400 - 300 + 697 + 349 diff --git a/include/config.h b/include/config.h index 3f77aa90..bf80ecb1 100644 --- a/include/config.h +++ b/include/config.h @@ -205,6 +205,7 @@ enum ProjectIdentifier { define_map_section_prefix, define_map_section_empty, define_map_section_count, + define_species_prefix, regex_behaviors, regex_obj_event_gfx, regex_items, @@ -219,7 +220,6 @@ enum ProjectIdentifier { regex_sign_facing_directions, regex_trainer_types, regex_music, - regex_species, }; enum ProjectFilePath { diff --git a/include/ui/wildmonchart.h b/include/ui/wildmonchart.h index 97cb53fa..36ab8619 100644 --- a/include/ui/wildmonchart.h +++ b/include/ui/wildmonchart.h @@ -13,16 +13,16 @@ class WildMonChart : public QWidget { Q_OBJECT public: - explicit WildMonChart(QWidget *parent, EncounterTableModel *table); + explicit WildMonChart(QWidget *parent, const EncounterTableModel *table); ~WildMonChart(); public slots: - void setTable(EncounterTableModel *table); + void setTable(const EncounterTableModel *table); void updateChart(); private: Ui::WildMonChart *ui; - EncounterTableModel *table; + const EncounterTableModel *table; }; #endif // WILDMONCHART_H diff --git a/src/config.cpp b/src/config.cpp index 16853e8f..fae8bac7 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -109,6 +109,7 @@ const QMap> ProjectConfig::defaultIde {ProjectIdentifier::define_map_section_prefix, {"define_map_section_prefix", "MAPSEC_"}}, {ProjectIdentifier::define_map_section_empty, {"define_map_section_empty", "NONE"}}, {ProjectIdentifier::define_map_section_count, {"define_map_section_count", "COUNT"}}, + {ProjectIdentifier::define_species_prefix, {"define_species_prefix", "SPECIES_"}}, // Regex {ProjectIdentifier::regex_behaviors, {"regex_behaviors", "\\bMB_"}}, {ProjectIdentifier::regex_obj_event_gfx, {"regex_obj_event_gfx", "\\bOBJ_EVENT_GFX_"}}, @@ -124,7 +125,6 @@ const QMap> ProjectConfig::defaultIde {ProjectIdentifier::regex_sign_facing_directions, {"regex_sign_facing_directions", "\\bBG_EVENT_PLAYER_FACING_"}}, {ProjectIdentifier::regex_trainer_types, {"regex_trainer_types", "\\bTRAINER_TYPE_"}}, {ProjectIdentifier::regex_music, {"regex_music", "\\b(SE|MUS)_"}}, - {ProjectIdentifier::regex_species, {"regex_species", "\\bSPECIES_"}}, }; const QMap> ProjectConfig::defaultPaths = { diff --git a/src/project.cpp b/src/project.cpp index 7048812a..1d37b3ea 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -2606,7 +2606,7 @@ bool Project::readSpeciesIconPaths() { const QMap iconIncbins = parser.readCIncbinMulti(incfilename); // Read species constants. If this fails we can get them from the icon table (but we shouldn't rely on it). - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_species)}; + const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::define_species_prefix)}; const QString constantsFilename = projectConfig.getFilePath(ProjectFilePath::constants_species); fileWatcher.addPath(root + "/" + constantsFilename); QStringList speciesNames = parser.readCDefineNames(constantsFilename, prefixes); diff --git a/src/ui/wildmonchart.cpp b/src/ui/wildmonchart.cpp index ee73a4dd..eccec380 100644 --- a/src/ui/wildmonchart.cpp +++ b/src/ui/wildmonchart.cpp @@ -1,16 +1,14 @@ #include "wildmonchart.h" #include "ui_wildmonchart.h" +#include "config.h" #include "log.h" #include -// TODO: Conditional QtCharts -> QtGraphs -// TODO: Handle if num pokemon < values -// TODO: Smarter value precision for %s -// TODO: Move level range onto graph? +// TODO: Make level range its own chart(s)? // TODO: Draw species icons below legend icons? -// TODO: Match group order in chart visually to group order in table +// TODO: Add hover behavior to display species name (and click prompt?) struct ChartData { int minLevel; @@ -18,7 +16,7 @@ struct ChartData { QMap values; // One value for each wild encounter group }; -WildMonChart::WildMonChart(QWidget *parent, EncounterTableModel *table) : +WildMonChart::WildMonChart(QWidget *parent, const EncounterTableModel *table) : QWidget(parent), ui(new Ui::WildMonChart) { @@ -35,22 +33,26 @@ WildMonChart::~WildMonChart() { delete ui; }; -void WildMonChart::setTable(EncounterTableModel *table) { +void WildMonChart::setTable(const EncounterTableModel *table) { this->table = table; updateChart(); } +static const bool showLevelRange = false; + void WildMonChart::updateChart() { if (!this->table) return; + setWindowTitle(QString("Wild Pokémon Summary -- %1").arg(this->table->encounterField().name)); + // Read data about encounter groups, e.g. for "fishing_mons" we want to know indexes 2-4 belong to good_rod (group index 1). // Each group will be represented as a separate bar on the graph. QList groupNames; QMap tableIndexToGroupIndex; int groupIndex = 0; - for (auto groupPair : table->encounterField().groups) { - groupNames.append(groupPair.first); + for (auto groupPair : this->table->encounterField().groups) { + groupNames.prepend(groupPair.first); for (auto i : groupPair.second) { tableIndexToGroupIndex.insert(i, groupIndex); } @@ -59,8 +61,8 @@ void WildMonChart::updateChart() { const int numGroups = qMax(1, groupNames.length()); // Implicitly 1 group when none are listed // Read data from the table, combining data for duplicate species entries - const QList tableValues = table->percentages(); - const QVector tablePokemon = table->encounterData().wildPokemon; + const QList tableValues = this->table->percentages(); + const QVector tablePokemon = this->table->encounterData().wildPokemon; QMap speciesToChartData; for (int i = 0; i < qMin(tableValues.length(), tablePokemon.length()); i++) { const double value = tableValues.at(i); @@ -86,28 +88,31 @@ void WildMonChart::updateChart() { } // Populate chart - //const QString speciesPrefix = projectConfig.getIdentifier(ProjectIdentifier::regex_species); // TODO: Change regex to prefix QList barSets; - const QString speciesPrefix = "SPECIES_"; + const QString speciesPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_species_prefix); for (auto mapPair = speciesToChartData.cbegin(), end = speciesToChartData.cend(); mapPair != end; mapPair++) { const ChartData entry = mapPair.value(); // Strip 'SPECIES_' prefix - QString species = mapPair.key(); - if (species.startsWith(speciesPrefix)) - species.remove(0, speciesPrefix.length()); + QString label = mapPair.key(); + if (label.startsWith(speciesPrefix)) + label.remove(0, speciesPrefix.length()); - // Create label for legend - QString label = QString("%1\nLv %2").arg(species).arg(entry.minLevel); - if (entry.minLevel != entry.maxLevel) - label.append(QString("-%1").arg(entry.maxLevel)); + // Add level range to label + if (showLevelRange) { + if (entry.minLevel == entry.maxLevel) + label.append(QString(" (Lv %1)").arg(entry.minLevel)); + else + label.append(QString(" (Lv %1-%2)").arg(entry.minLevel).arg(entry.maxLevel)); + } - // Add encounter chance data auto set = new QBarSet(label); - for (int i = 0; i < numGroups; i++) + + // Add encounter chance data (in reverse order, to match the table's group order visually) + for (int i = numGroups - 1; i >= 0; i--) set->append(entry.values.value(i, 0)); - // Insert bar set in order of total value + // Insert bar set. We order them from lowest to highest total, left-to-right. int i = 0; for (; i < barSets.length(); i++){ if (barSets.at(i)->sum() > set->sum()) @@ -118,6 +123,7 @@ void WildMonChart::updateChart() { auto series = new QHorizontalPercentBarSeries(); series->setLabelsVisible(); + //series->setLabelsPrecision(x); // This appears to have no effect for any value 'x'? Ideally we'd display 1-2 decimal places series->append(barSets); auto chart = new QChart(); @@ -127,8 +133,14 @@ void WildMonChart::updateChart() { chart->legend()->setShowToolTips(true); chart->legend()->setAlignment(Qt::AlignBottom); - // X-axis is the values (percentages) + // X-axis is the values (percentages). We're already showing percentages on the bar, so we just display 0/50/100% auto axisX = new QValueAxis(); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)) + // Not critical, but the percentage ticks on the x-axis have no need for decimals. + // This property doesn't exist prior to Qt 6.7 + axisX->setLabelDecimals(0); +#endif + axisX->setTickCount(3); chart->addAxis(axisX, Qt::AlignBottom); series->attachAxis(axisX); @@ -142,4 +154,10 @@ void WildMonChart::updateChart() { delete ui->chartView->chart(); ui->chartView->setChart(chart); + + // Turn off the animation once it's played, otherwise it replays any time the window changes size. + QTimer::singleShot(chart->animationDuration() + 500, [this] { + if (ui->chartView->chart()) + ui->chartView->chart()->setAnimationOptions(QChart::NoAnimation); + }); }