porymap/src/ui/wildmonsearch.cpp
2025-01-28 14:09:24 -05:00

159 lines
6.5 KiB
C++

#include "wildmonsearch.h"
#include "ui_wildmonsearch.h"
#include "project.h"
enum ResultsColumn {
Group,
Field,
Level,
Chance,
};
enum ResultsDataRole {
MapName = Qt::UserRole,
};
WildMonSearch::WildMonSearch(Project *project, QWidget *parent) :
QDialog(parent),
ui(new Ui::WildMonSearch),
project(project)
{
setAttribute(Qt::WA_DeleteOnClose);
ui->setupUi(this);
// Set up species combo box
ui->comboBox_Search->addItems(project->speciesToIconPath.keys());
ui->comboBox_Search->setCurrentText(QString());
ui->comboBox_Search->lineEdit()->setPlaceholderText(Project::getEmptySpeciesName());
connect(ui->comboBox_Search, &QComboBox::currentTextChanged, this, &WildMonSearch::updateResults);
// Set up table header
static const QStringList labels = {"Group", "Field", "Level", "Chance"};
ui->table_Results->setHorizontalHeaderLabels(labels);
ui->table_Results->horizontalHeader()->setSectionResizeMode(ResultsColumn::Group, QHeaderView::Stretch);
ui->table_Results->horizontalHeader()->setSectionResizeMode(ResultsColumn::Field, QHeaderView::ResizeToContents);
ui->table_Results->horizontalHeader()->setSectionResizeMode(ResultsColumn::Level, QHeaderView::ResizeToContents);
ui->table_Results->horizontalHeader()->setSectionResizeMode(ResultsColumn::Chance, QHeaderView::ResizeToContents);
// Table is read-only
ui->table_Results->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->table_Results->setSelectionMode(QAbstractItemView::NoSelection);
connect(ui->table_Results, &QTableWidget::cellDoubleClicked, this, &WildMonSearch::cellDoubleClicked);
refresh();
}
WildMonSearch::~WildMonSearch() {
delete ui;
}
void WildMonSearch::refresh() {
this->resultsCache.clear();
updatePercentageStrings();
updateResults(ui->comboBox_Search->currentText());
}
void WildMonSearch::addTableEntry(const RowData &rowData) {
int row = ui->table_Results->rowCount();
ui->table_Results->insertRow(row);
auto groupItem = new QTableWidgetItem(rowData.groupName);
groupItem->setData(ResultsDataRole::MapName, rowData.mapName);
ui->table_Results->setItem(row, ResultsColumn::Group, groupItem);
ui->table_Results->setItem(row, ResultsColumn::Field, new QTableWidgetItem(rowData.fieldName));
ui->table_Results->setItem(row, ResultsColumn::Level, new QTableWidgetItem(rowData.levelRange));
ui->table_Results->setItem(row, ResultsColumn::Chance, new QTableWidgetItem(rowData.chance));
}
QList<WildMonSearch::RowData> WildMonSearch::search(const QString &species) const {
QList<RowData> results;
for (const auto &keyPair : this->project->wildMonData) {
QString mapConstant = keyPair.first;
for (const auto &grouplLabelPair : this->project->wildMonData[mapConstant]) {
QString groupName = grouplLabelPair.first;
WildPokemonHeader encounterHeader = this->project->wildMonData[mapConstant][groupName];
for (const auto &fieldNamePair : encounterHeader.wildMons) {
QString fieldName = fieldNamePair.first;
WildMonInfo monInfo = encounterHeader.wildMons[fieldName];
for (int slot = 0; slot < monInfo.wildPokemon.length(); slot++) {
const WildPokemon wildMon = monInfo.wildPokemon.at(slot);
if (wildMon.species == species) {
RowData rowData;
rowData.groupName = groupName;
rowData.fieldName = fieldName;
rowData.mapName = this->project->mapConstantsToMapNames.value(mapConstant, mapConstant);
// If min and max level are the same display a single number, otherwise display a level range.
rowData.levelRange = (wildMon.minLevel == wildMon.maxLevel) ? QString::number(wildMon.minLevel)
: QString("%1-%2").arg(wildMon.minLevel).arg(wildMon.maxLevel);
rowData.chance = this->percentageStrings[fieldName][slot];
results.append(rowData);
}
}
}
}
}
return results;
}
void WildMonSearch::updatePercentageStrings() {
this->percentageStrings.clear();
for (const EncounterField &monField : this->project->wildMonFields) {
QMap<int,QString> slotToPercentString;
auto percentages = getWildEncounterPercentages(monField);
for (int i = 0; i < percentages.length(); i++) {
slotToPercentString.insert(i, QString::number(percentages.at(i) * 100, 'f', 2) + "%");
}
this->percentageStrings[monField.name] = slotToPercentString;
}
}
void WildMonSearch::updateResults(const QString &species) {
ui->speciesIcon->setPixmap(this->project->getSpeciesIcon(species));
ui->table_Results->clearContents();
ui->table_Results->setRowCount(0);
// Note: Per Qt docs, sorting should be disabled while populating the table to avoid it interfering with insertion order.
ui->table_Results->setSortingEnabled(false);
if (ui->comboBox_Search->findText(species) < 0)
return; // Not a species name, no need to search wild encounter data.
const QList<RowData> results = this->resultsCache.value(species, search(species));
if (results.isEmpty()) {
static const RowData noResults = {
.groupName = QStringLiteral("Species not found."),
.fieldName = QStringLiteral("--"),
.levelRange = QStringLiteral("--"),
.chance = QStringLiteral("--"),
};
addTableEntry(noResults);
} else {
for (const auto &entry : results) {
addTableEntry(entry);
}
}
// TODO: This does a lexical sort... We might need custom item delegates to get proper numerical sorting in this table.
ui->table_Results->setSortingEnabled(true);
this->resultsCache.insert(species, results);
}
// Double-clicking row data opens the corresponding map/table on the Wild Pokémon tab.
void WildMonSearch::cellDoubleClicked(int row, int) {
auto groupItem = ui->table_Results->item(row, ResultsColumn::Group);
auto fieldItem = ui->table_Results->item(row, ResultsColumn::Field);
if (!groupItem || !fieldItem)
return;
const QString mapName = groupItem->data(ResultsDataRole::MapName).toString();
if (mapName.isEmpty())
return;
emit openWildMonTableRequested(mapName, groupItem->text(), fieldItem->text());
}