diff --git a/forms/projectsettingseditor.ui b/forms/projectsettingseditor.ui
index 05598b8f..c840d331 100644
--- a/forms/projectsettingseditor.ui
+++ b/forms/projectsettingseditor.ui
@@ -39,7 +39,7 @@
0
0
570
- 692
+ 680
@@ -94,7 +94,7 @@
...
-
+
:/icons/folder.ico:/icons/folder.ico
@@ -164,7 +164,7 @@
...
-
+
:/icons/folder.ico:/icons/folder.ico
@@ -248,7 +248,7 @@
...
-
+
:/icons/folder.ico:/icons/folder.ico
@@ -1197,23 +1197,62 @@
0
0
570
- 840
+ 927
+ -
+
+
+ Tab Icon
+
+
+
-
+
+
+ false
+
+
+ ...
+
+
+
+ :/icons/folder.ico:/icons/folder.ico
+
+
+
+ -
+
+
+ false
+
+
+ <html><head/><body><p>The image file path to use for the icon of the Events tab.</p></body></html>
+
+
+ true
+
+
+
+ -
+
+
+ <html><head/><body><p>The icon that will be displayed for the Events tab in the editor. If 'Automatic' is chosen, the icon will be a random player character from the project's base game version. If 'Custom' is chosen an image file path may be specified.</p></body></html>
+
+
+ false
+
+
+
+
+
+
-
Default Icons
-
-
-
-
- Triggers
-
-
-
-
@@ -1221,23 +1260,31 @@
- -
-
+
-
+
- <html><head/><body><p>The icon that will be used to represent Warp events</p></body></html>
+ <html><head/><body><p>The icon that will be used to represent BG events</p></body></html>
true
- -
-
-
- <html><head/><body><p>The icon that will be used to represent Heal Location events</p></body></html>
+
-
+
+
+ ...
-
- true
+
+
+ :/icons/folder.ico:/icons/folder.ico
+
+
+
+ -
+
+
+ Objects
@@ -1248,6 +1295,24 @@
+ -
+
+
+ Triggers
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/icons/folder.ico:/icons/folder.ico
+
+
+
-
@@ -1265,10 +1330,56 @@
- -
-
+
-
+
+
+ <html><head/><body><p>The icon that will be used to represent Warp events</p></body></html>
+
+
+ true
+
+
+
+ -
+
- Objects
+ ...
+
+
+
+ :/icons/folder.ico:/icons/folder.ico
+
+
+
+ -
+
+
+ <html><head/><body><p>The icon that will be used to represent Heal Location events</p></body></html>
+
+
+ true
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/icons/folder.ico:/icons/folder.ico
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/icons/folder.ico:/icons/folder.ico
@@ -1282,71 +1393,6 @@
- -
-
-
- <html><head/><body><p>The icon that will be used to represent BG events</p></body></html>
-
-
- true
-
-
-
- -
-
-
- ...
-
-
-
- :/icons/folder.ico:/icons/folder.ico
-
-
-
- -
-
-
- ...
-
-
-
- :/icons/folder.ico:/icons/folder.ico
-
-
-
- -
-
-
- ...
-
-
-
- :/icons/folder.ico:/icons/folder.ico
-
-
-
- -
-
-
- ...
-
-
-
- :/icons/folder.ico:/icons/folder.ico
-
-
-
- -
-
-
- ...
-
-
-
- :/icons/folder.ico:/icons/folder.ico
-
-
-
@@ -1365,7 +1411,7 @@
...
-
+
:/icons/delete.ico:/icons/delete.ico
@@ -1418,7 +1464,7 @@
...
-
+
:/icons/add.ico:/icons/add.ico
@@ -1628,7 +1674,7 @@
0
0
544
- 338
+ 341
@@ -1657,7 +1703,7 @@
Add Global Constants File...
-
+
:/icons/add.ico:/icons/add.ico
@@ -1668,7 +1714,7 @@
...
-
+
:/icons/help.ico:/icons/help.ico
@@ -1708,7 +1754,7 @@
...
-
+
:/icons/help.ico:/icons/help.ico
@@ -1745,7 +1791,7 @@
0
0
544
- 421
+ 425
@@ -1774,7 +1820,7 @@
Add Global Constant...
-
+
:/icons/add.ico:/icons/add.ico
@@ -1840,8 +1886,6 @@
-
-
-
+
diff --git a/include/config.h b/include/config.h
index 3f441229..2e99dc3e 100644
--- a/include/config.h
+++ b/include/config.h
@@ -335,6 +335,7 @@ public:
this->filePaths.clear();
this->eventIconPaths.clear();
this->pokemonIconPaths.clear();
+ this->eventsTabIconPath = QString();
this->collisionSheetPath = QString();
this->collisionSheetSize = QSize(2, 16);
this->playerViewDistance = QMargins(GBA_H_DIST_TO_CENTER, GBA_V_DIST_TO_CENTER, GBA_H_DIST_TO_CENTER, GBA_V_DIST_TO_CENTER);
@@ -356,6 +357,9 @@ public:
static const QStringList versionStrings;
static BaseGameVersion stringToBaseGameVersion(const QString &string);
+ static QString getPlayerIconPath(BaseGameVersion baseGameVersion, int character);
+ static QIcon getPlayerIcon(BaseGameVersion baseGameVersion, int character);
+
void reset(BaseGameVersion baseGameVersion);
void setFilePath(ProjectFilePath pathId, const QString &path);
void setFilePath(const QString &pathId, const QString &path);
@@ -415,6 +419,7 @@ public:
uint16_t unusedTileCovered;
uint16_t unusedTileSplit;
bool mapAllowFlagsEnabled;
+ QString eventsTabIconPath;
QString collisionSheetPath;
QSize collisionSheetSize;
QMargins playerViewDistance;
diff --git a/resources/icons/player/brendan_em.ico b/resources/icons/player/brendan_em.ico
new file mode 100644
index 00000000..2c896c44
Binary files /dev/null and b/resources/icons/player/brendan_em.ico differ
diff --git a/resources/icons/player/brendan_rs.ico b/resources/icons/player/brendan_rs.ico
new file mode 100644
index 00000000..c3385a4d
Binary files /dev/null and b/resources/icons/player/brendan_rs.ico differ
diff --git a/resources/icons/player/green.ico b/resources/icons/player/green.ico
new file mode 100644
index 00000000..3cdada55
Binary files /dev/null and b/resources/icons/player/green.ico differ
diff --git a/resources/icons/player/may_em.ico b/resources/icons/player/may_em.ico
new file mode 100644
index 00000000..ffa56bab
Binary files /dev/null and b/resources/icons/player/may_em.ico differ
diff --git a/resources/icons/player/may_rs.ico b/resources/icons/player/may_rs.ico
new file mode 100644
index 00000000..7450d620
Binary files /dev/null and b/resources/icons/player/may_rs.ico differ
diff --git a/resources/icons/viewsprites.ico b/resources/icons/player/red.ico
similarity index 100%
rename from resources/icons/viewsprites.ico
rename to resources/icons/player/red.ico
diff --git a/resources/images.qrc b/resources/images.qrc
index 41789a6e..8d6af6fd 100644
--- a/resources/images.qrc
+++ b/resources/images.qrc
@@ -46,9 +46,14 @@
icons/sort_number.ico
icons/tall_grass.ico
icons/minimap.ico
- icons/viewsprites.ico
icons/application_form_edit.ico
icons/connections.ico
+ icons/player/brendan_em.ico
+ icons/player/brendan_rs.ico
+ icons/player/green.ico
+ icons/player/may_em.ico
+ icons/player/may_rs.ico
+ icons/player/red.ico
icons/ui/dark/checkbox_checked_disabled.png
icons/ui/dark/checkbox_checked_disabled@2x.png
icons/ui/dark/checkbox_checked.png
diff --git a/src/config.cpp b/src/config.cpp
index 45144a2d..7914cdce 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -731,6 +731,32 @@ BaseGameVersion ProjectConfig::stringToBaseGameVersion(const QString &string) {
return version;
}
+QString ProjectConfig::getPlayerIconPath(BaseGameVersion baseGameVersion, int character) {
+ switch (baseGameVersion) {
+ case BaseGameVersion::pokeemerald: {
+ static const QStringList paths = { QStringLiteral(":/icons/player/brendan_em.ico"),
+ QStringLiteral(":/icons/player/may_em.ico"), };
+ return paths.value(character);
+ }
+ case BaseGameVersion::pokefirered: {
+ static const QStringList paths = { QStringLiteral(":/icons/player/red.ico"),
+ QStringLiteral(":/icons/player/green.ico"), };
+ return paths.value(character);
+ }
+ case BaseGameVersion::pokeruby: {
+ static const QStringList paths = { QStringLiteral(":/icons/player/brendan_rs.ico"),
+ QStringLiteral(":/icons/player/may_rs.ico"), };
+ return paths.value(character);
+ }
+ default: break;
+ }
+ return QString();
+}
+
+QIcon ProjectConfig::getPlayerIcon(BaseGameVersion baseGameVersion, int character) {
+ return QIcon(getPlayerIconPath(baseGameVersion, character));
+}
+
ProjectConfig projectConfig;
QString ProjectConfig::getConfigFilepath() {
@@ -868,6 +894,8 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
this->eventIconPaths[Event::Group::Heal] = value;
} else if (key.startsWith("pokemon_icon_path/")) {
this->pokemonIconPaths.insert(key.mid(QStringLiteral("pokemon_icon_path/").length()), value);
+ } else if (key == "events_tab_icon_path") {
+ this->eventsTabIconPath = value;
} else if (key == "collision_sheet_path") {
this->collisionSheetPath = value;
} else if (key == "collision_sheet_width") {
@@ -987,6 +1015,7 @@ QMap ProjectConfig::getKeyValueMap() {
for (auto it = this->identifiers.constBegin(); it != this->identifiers.constEnd(); it++) {
map.insert("ident/"+defaultIdentifiers.value(it.key()).first, it.value());
}
+ map.insert("events_tab_icon_path", this->eventsTabIconPath);
map.insert("collision_sheet_path", this->collisionSheetPath);
map.insert("collision_sheet_width", QString::number(this->collisionSheetSize.width()));
map.insert("collision_sheet_height", QString::number(this->collisionSheetSize.height()));
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 16b24f1e..6a54bce1 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -249,7 +249,7 @@ void MainWindow::initCustomUI() {
static const QMap mainTabIcons = {
{MainTab::Map, QIcon(QStringLiteral(":/icons/minimap.ico"))},
- {MainTab::Events, QIcon(QStringLiteral(":/icons/viewsprites.ico"))},
+ {MainTab::Events, ProjectConfig::getPlayerIcon(BaseGameVersion::pokefirered, 0)}, // Arbitrary default
{MainTab::Header, QIcon(QStringLiteral(":/icons/application_form_edit.ico"))},
{MainTab::Connections, QIcon(QStringLiteral(":/icons/connections.ico"))},
{MainTab::WildPokemon, QIcon(QStringLiteral(":/icons/tall_grass.ico"))},
@@ -1305,6 +1305,21 @@ bool MainWindow::setProjectUI() {
ui->mapCustomAttributesFrame->table()->setRestrictedKeys(project->getTopLevelMapFields());
+ // Set a version dependent player icon (or user-chosen icon) for the Events tab.
+ QIcon eventTabIcon;
+ if (!projectConfig.eventsTabIconPath.isEmpty()) {
+ eventTabIcon = QIcon(project->getExistingFilepath(projectConfig.eventsTabIconPath));
+ if (eventTabIcon.isNull()) {
+ logWarn(QString("Failed to load custom Events tab icon '%1'.").arg(projectConfig.eventsTabIconPath));
+ }
+ }
+ if (eventTabIcon.isNull()) {
+ // We randomly choose between the available characters for ~flavor~.
+ // For now, this correctly assumes all versions have 2 icons.
+ eventTabIcon = ProjectConfig::getPlayerIcon(projectConfig.baseGameVersion, QRandomGenerator::global()->bounded(0, 2));
+ }
+ ui->mainTabBar->setTabIcon(MainTab::Events, eventTabIcon);
+
return true;
}
diff --git a/src/ui/projectsettingseditor.cpp b/src/ui/projectsettingseditor.cpp
index 166874ee..fa2d3ee2 100644
--- a/src/ui/projectsettingseditor.cpp
+++ b/src/ui/projectsettingseditor.cpp
@@ -67,6 +67,7 @@ void ProjectSettingsEditor::connectSignals() {
connect(ui->button_BGsIcon, &QAbstractButton::clicked, [this](bool) { this->chooseImageFile(ui->lineEdit_BGsIcon); });
connect(ui->button_HealLocationsIcon, &QAbstractButton::clicked, [this](bool) { this->chooseImageFile(ui->lineEdit_HealLocationsIcon); });
connect(ui->button_PokemonIcon, &QAbstractButton::clicked, [this](bool) { this->chooseImageFile(ui->lineEdit_PokemonIcon); });
+ connect(ui->button_EventsTabIcon, &QAbstractButton::clicked, [this](bool) { this->chooseImageFile(ui->lineEdit_EventsTabIcon); });
// Display a warning if a mask value overlaps with another mask in its group.
@@ -113,6 +114,20 @@ void ProjectSettingsEditor::initUi() {
ui->comboBox_BaseGameVersion->addItems(ProjectConfig::versionStrings);
ui->comboBox_AttributesSize->addItems({"1", "2", "4"});
+ ui->comboBox_EventsTabIcon->addItem("Automatic", "");
+ ui->comboBox_EventsTabIcon->addItem("Brendan (Emerald)", ProjectConfig::getPlayerIconPath(BaseGameVersion::pokeemerald, 0));
+ ui->comboBox_EventsTabIcon->addItem("Brendan (R/S)", ProjectConfig::getPlayerIconPath(BaseGameVersion::pokeruby, 0));
+ ui->comboBox_EventsTabIcon->addItem("May (Emerald)", ProjectConfig::getPlayerIconPath(BaseGameVersion::pokeemerald, 1));
+ ui->comboBox_EventsTabIcon->addItem("May (R/S)", ProjectConfig::getPlayerIconPath(BaseGameVersion::pokeruby, 1));
+ ui->comboBox_EventsTabIcon->addItem("Red", ProjectConfig::getPlayerIconPath(BaseGameVersion::pokefirered, 0));
+ ui->comboBox_EventsTabIcon->addItem("Green", ProjectConfig::getPlayerIconPath(BaseGameVersion::pokefirered, 1));
+ ui->comboBox_EventsTabIcon->addItem("Custom", "Custom");
+ connect(ui->comboBox_EventsTabIcon, QOverload::of(&NoScrollComboBox::currentIndexChanged), [this](int index) {
+ bool usingCustom = (index == ui->comboBox_EventsTabIcon->findText("Custom"));
+ ui->lineEdit_EventsTabIcon->setVisible(usingCustom);
+ ui->button_EventsTabIcon->setVisible(usingCustom);
+ });
+
// Validate that the border metatiles text is a comma-separated list of metatile values
static const QString regex_Hex = "(0[xX])?[A-Fa-f0-9]+";
static const QRegularExpression expression_HexList(QString("^(%1,)*%1$").arg(regex_Hex)); // Comma-separated list of hex values
@@ -520,6 +535,15 @@ void ProjectSettingsEditor::refresh() {
}
this->setWarpBehaviorsList(behaviorNames);
+ int index = ui->comboBox_EventsTabIcon->findData(projectConfig.eventsTabIconPath);
+ if (index < 0) {
+ index = ui->comboBox_EventsTabIcon->findData("Custom");
+ ui->lineEdit_EventsTabIcon->setText(projectConfig.eventsTabIconPath);
+ } else {
+ ui->lineEdit_EventsTabIcon->setText("");
+ }
+ ui->comboBox_EventsTabIcon->setCurrentIndex(index);
+
this->refreshing = false; // Allow signals
}
@@ -608,6 +632,16 @@ void ProjectSettingsEditor::save() {
for (auto i = this->editedPokemonIconPaths.cbegin(), end = this->editedPokemonIconPaths.cend(); i != end; i++)
projectConfig.setPokemonIconPath(i.key(), i.value());
+ QString eventsTabIconPath;
+ QVariant data = ui->comboBox_EventsTabIcon->currentData();
+ if (data.isValid() && data.canConvert()) {
+ eventsTabIconPath = data.toString();
+ if (eventsTabIconPath == "Custom") {
+ eventsTabIconPath = ui->lineEdit_EventsTabIcon->text();
+ }
+ }
+ projectConfig.eventsTabIconPath = eventsTabIconPath;
+
projectConfig.save();
userConfig.save();
porymapConfig.save();