From 43d4923e789a5bdb2286a756858b717721c91da2 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Thu, 16 Jun 2022 01:07:28 +0200 Subject: [PATCH 1/3] Config: Allow passing std::nullopt for the region in GetMemcardPath() to use the region as configured in the path itself. Falls back to the fallback region if no region is in the path. --- Source/Core/Core/Config/MainSettings.cpp | 26 +++++++++++++++++++----- Source/Core/Core/Config/MainSettings.h | 7 +++++-- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 01fd799846..85621d2f58 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -583,15 +583,15 @@ std::string GetBootROMPath(const std::string& region_directory) return path; } -std::string GetMemcardPath(ExpansionInterface::Slot slot, DiscIO::Region region, u16 size_mb) +std::string GetMemcardPath(ExpansionInterface::Slot slot, std::optional region, + u16 size_mb) { return GetMemcardPath(Config::Get(GetInfoForMemcardPath(slot)), slot, region, size_mb); } std::string GetMemcardPath(std::string configured_filename, ExpansionInterface::Slot slot, - DiscIO::Region region, u16 size_mb) + std::optional region, u16 size_mb) { - const std::string region_dir = Config::GetDirectoryForRegion(Config::ToGameCubeRegion(region)); const std::string blocks_string = size_mb < Memcard::MBIT_SIZE_MEMORY_CARD_2043 ? fmt::format(".{}", Memcard::MbitToFreeBlocks(size_mb)) : ""; @@ -600,8 +600,10 @@ std::string GetMemcardPath(std::string configured_filename, ExpansionInterface:: { // Use default memcard path if there is no user defined one. const bool is_slot_a = slot == ExpansionInterface::Slot::A; + const std::string region_string = Config::GetDirectoryForRegion( + Config::ToGameCubeRegion(region ? *region : Config::Get(Config::MAIN_FALLBACK_REGION))); return fmt::format("{}{}.{}{}.raw", File::GetUserPath(D_GCUSER_IDX), - is_slot_a ? GC_MEMCARDA : GC_MEMCARDB, region_dir, blocks_string); + is_slot_a ? GC_MEMCARDA : GC_MEMCARDB, region_string, blocks_string); } // Custom path is expected to be stored in the form of @@ -619,13 +621,27 @@ std::string GetMemcardPath(std::string configured_filename, ExpansionInterface:: constexpr std::string_view us_region = "." USA_DIR; constexpr std::string_view jp_region = "." JAP_DIR; constexpr std::string_view eu_region = "." EUR_DIR; + std::optional path_region = std::nullopt; if (StringEndsWith(name, us_region)) + { name = name.substr(0, name.size() - us_region.size()); + path_region = DiscIO::Region::NTSC_U; + } else if (StringEndsWith(name, jp_region)) + { name = name.substr(0, name.size() - jp_region.size()); + path_region = DiscIO::Region::NTSC_J; + } else if (StringEndsWith(name, eu_region)) + { name = name.substr(0, name.size() - eu_region.size()); + path_region = DiscIO::Region::PAL; + } - return fmt::format("{}{}.{}{}{}", dir, name, region_dir, blocks_string, ext); + const DiscIO::Region used_region = + region ? *region : (path_region ? *path_region : Config::Get(Config::MAIN_FALLBACK_REGION)); + return fmt::format("{}{}.{}{}{}", dir, name, + Config::GetDirectoryForRegion(Config::ToGameCubeRegion(used_region)), + blocks_string, ext); } } // namespace Config diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index e731e891b7..d8e682134b 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -343,8 +343,11 @@ DiscIO::Region ToGameCubeRegion(DiscIO::Region region); // The region argument must be valid for GameCube (i.e. must not be NTSC-K) const char* GetDirectoryForRegion(DiscIO::Region region); std::string GetBootROMPath(const std::string& region_directory); -std::string GetMemcardPath(ExpansionInterface::Slot slot, DiscIO::Region region, +// Builds the memory card according to the configuration with the given region and size. If the +// given region is std::nullopt, the region in the configured path is used if there is one, or the +// fallback region otherwise. +std::string GetMemcardPath(ExpansionInterface::Slot slot, std::optional region, u16 size_mb = 0x80); std::string GetMemcardPath(std::string configured_filename, ExpansionInterface::Slot slot, - DiscIO::Region region, u16 size_mb = 0x80); + std::optional region, u16 size_mb = 0x80); } // namespace Config From d11839fd649c4235adc2226b25250f97c78d61f3 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Wed, 19 Jan 2022 01:32:32 +0100 Subject: [PATCH 2/3] DolphinQt: Show raw memory card path and AGP cartridge path in config window. --- .../Core/DolphinQt/Settings/GameCubePane.cpp | 107 +++++++++++++++--- Source/Core/DolphinQt/Settings/GameCubePane.h | 13 +++ 2 files changed, 104 insertions(+), 16 deletions(-) diff --git a/Source/Core/DolphinQt/Settings/GameCubePane.cpp b/Source/Core/DolphinQt/Settings/GameCubePane.cpp index cd5cd258df..0e6c19aef1 100644 --- a/Source/Core/DolphinQt/Settings/GameCubePane.cpp +++ b/Source/Core/DolphinQt/Settings/GameCubePane.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -100,6 +101,21 @@ void GameCubePane::CreateWidgets() m_slot_buttons[slot]->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } + for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS) + { + m_memcard_path_layouts[slot] = new QHBoxLayout(); + m_memcard_path_labels[slot] = new QLabel(tr("Memory Card Path:")); + m_memcard_paths[slot] = new QLineEdit(); + m_memcard_path_layouts[slot]->addWidget(m_memcard_path_labels[slot]); + m_memcard_path_layouts[slot]->addWidget(m_memcard_paths[slot]); + + m_agp_path_layouts[slot] = new QHBoxLayout(); + m_agp_path_labels[slot] = new QLabel(tr("GBA Cartridge Path:")); + m_agp_paths[slot] = new QLineEdit(); + m_agp_path_layouts[slot]->addWidget(m_agp_path_labels[slot]); + m_agp_path_layouts[slot]->addWidget(m_agp_paths[slot]); + } + // Add slot devices for (const auto device : {EXIDeviceType::None, EXIDeviceType::Dummy, EXIDeviceType::MemoryCard, EXIDeviceType::MemoryCardFolder, EXIDeviceType::Gecko, @@ -127,15 +143,34 @@ void GameCubePane::CreateWidgets() static_cast(device)); } - device_layout->addWidget(new QLabel(tr("Slot A:")), 0, 0); - device_layout->addWidget(m_slot_combos[ExpansionInterface::Slot::A], 0, 1); - device_layout->addWidget(m_slot_buttons[ExpansionInterface::Slot::A], 0, 2); - device_layout->addWidget(new QLabel(tr("Slot B:")), 1, 0); - device_layout->addWidget(m_slot_combos[ExpansionInterface::Slot::B], 1, 1); - device_layout->addWidget(m_slot_buttons[ExpansionInterface::Slot::B], 1, 2); - device_layout->addWidget(new QLabel(tr("SP1:")), 2, 0); - device_layout->addWidget(m_slot_combos[ExpansionInterface::Slot::SP1], 2, 1); - device_layout->addWidget(m_slot_buttons[ExpansionInterface::Slot::SP1], 2, 2); + { + int row = 0; + device_layout->addWidget(new QLabel(tr("Slot A:")), row, 0); + device_layout->addWidget(m_slot_combos[ExpansionInterface::Slot::A], row, 1); + device_layout->addWidget(m_slot_buttons[ExpansionInterface::Slot::A], row, 2); + + ++row; + device_layout->addLayout(m_memcard_path_layouts[ExpansionInterface::Slot::A], row, 0, 1, 3); + + ++row; + device_layout->addLayout(m_agp_path_layouts[ExpansionInterface::Slot::A], row, 0, 1, 3); + + ++row; + device_layout->addWidget(new QLabel(tr("Slot B:")), row, 0); + device_layout->addWidget(m_slot_combos[ExpansionInterface::Slot::B], row, 1); + device_layout->addWidget(m_slot_buttons[ExpansionInterface::Slot::B], row, 2); + + ++row; + device_layout->addLayout(m_memcard_path_layouts[ExpansionInterface::Slot::B], row, 0, 1, 3); + + ++row; + device_layout->addLayout(m_agp_path_layouts[ExpansionInterface::Slot::B], row, 0, 1, 3); + + ++row; + device_layout->addWidget(new QLabel(tr("SP1:")), row, 0); + device_layout->addWidget(m_slot_combos[ExpansionInterface::Slot::SP1], row, 1); + device_layout->addWidget(m_slot_buttons[ExpansionInterface::Slot::SP1], row, 2); + } #ifdef HAS_LIBMGBA // GBA Settings @@ -205,6 +240,17 @@ void GameCubePane::ConnectWidgets() connect(m_slot_buttons[slot], &QPushButton::clicked, [this, slot] { OnConfigPressed(slot); }); } + for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS) + { + connect(m_memcard_paths[slot], &QLineEdit::editingFinished, [this, slot] { + // revert path change on failure + if (!SetMemcard(slot, m_memcard_paths[slot]->text())) + LoadSettings(); + }); + connect(m_agp_paths[slot], &QLineEdit::editingFinished, + [this, slot] { SetAGPRom(slot, m_agp_paths[slot]->text()); }); + } + #ifdef HAS_LIBMGBA // GBA Settings connect(m_gba_threads, &QCheckBox::stateChanged, this, &GameCubePane::SaveSettings); @@ -257,6 +303,10 @@ void GameCubePane::UpdateButton(ExpansionInterface::Slot slot) has_config = (device == ExpansionInterface::EXIDeviceType::MemoryCard || device == ExpansionInterface::EXIDeviceType::AGP || device == ExpansionInterface::EXIDeviceType::Microphone); + m_memcard_path_labels[slot]->setHidden(device != ExpansionInterface::EXIDeviceType::MemoryCard); + m_memcard_paths[slot]->setHidden(device != ExpansionInterface::EXIDeviceType::MemoryCard); + m_agp_path_labels[slot]->setHidden(device != ExpansionInterface::EXIDeviceType::AGP); + m_agp_paths[slot]->setHidden(device != ExpansionInterface::EXIDeviceType::AGP); break; case ExpansionInterface::Slot::SP1: has_config = (device == ExpansionInterface::EXIDeviceType::Ethernet || @@ -315,8 +365,17 @@ void GameCubePane::BrowseMemcard(ExpansionInterface::Slot slot) QString::fromStdString(File::GetUserPath(D_GCUSER_IDX)), tr("GameCube Memory Cards (*.raw *.gcp)"), 0, QFileDialog::DontConfirmOverwrite); + if (!filename.isEmpty()) + SetMemcard(slot, filename); +} + +bool GameCubePane::SetMemcard(ExpansionInterface::Slot slot, const QString& filename) +{ if (filename.isEmpty()) - return; + { + ModalMessageBox::critical(this, tr("Error"), tr("Cannot set memory card to an empty path.")); + return false; + } const std::string raw_path = WithUnifiedPathSeparators(QFileInfo(filename).absoluteFilePath().toStdString()); @@ -338,7 +397,7 @@ void GameCubePane::BrowseMemcard(ExpansionInterface::Slot slot) .arg(QString::fromStdString(PathToFileName(us_path))) .arg(QString::fromStdString(PathToFileName(eu_path))) .arg(QString::fromStdString(PathToFileName(jp_path)))); - return; + return false; } // Memcard validity checks @@ -355,7 +414,7 @@ void GameCubePane::BrowseMemcard(ExpansionInterface::Slot slot) tr("The file\n%1\nis either corrupted or not a GameCube memory card file.\n%2") .arg(QString::fromStdString(path)) .arg(GCMemcardManager::GetErrorMessagesForErrorCode(error_code))); - return; + return false; } } } @@ -375,7 +434,7 @@ void GameCubePane::BrowseMemcard(ExpansionInterface::Slot slot) this, tr("Error"), tr("The same file can't be used in multiple slots; it is already used by %1.") .arg(QString::fromStdString(fmt::to_string(other_slot)))); - return; + return false; } } @@ -394,6 +453,9 @@ void GameCubePane::BrowseMemcard(ExpansionInterface::Slot slot) ExpansionInterface::ChangeDevice(slot, ExpansionInterface::EXIDeviceType::MemoryCard); } } + + LoadSettings(); + return true; } void GameCubePane::BrowseAGPRom(ExpansionInterface::Slot slot) @@ -404,10 +466,13 @@ void GameCubePane::BrowseAGPRom(ExpansionInterface::Slot slot) this, tr("Choose a file to open"), QString::fromStdString(File::GetUserPath(D_GCUSER_IDX)), tr("Game Boy Advance Carts (*.gba)"), 0, QFileDialog::DontConfirmOverwrite); - if (filename.isEmpty()) - return; + if (!filename.isEmpty()) + SetAGPRom(slot, filename); +} - QString path_abs = QFileInfo(filename).absoluteFilePath(); +void GameCubePane::SetAGPRom(ExpansionInterface::Slot slot, const QString& filename) +{ + QString path_abs = filename.isEmpty() ? QString() : QFileInfo(filename).absoluteFilePath(); QString path_old = QFileInfo(QString::fromStdString(Config::Get(Config::GetInfoForAGPCartPath(slot)))) @@ -423,6 +488,8 @@ void GameCubePane::BrowseAGPRom(ExpansionInterface::Slot slot) // we might as well do it for the AGP too. ExpansionInterface::ChangeDevice(slot, ExpansionInterface::EXIDeviceType::AGP); } + + LoadSettings(); } void GameCubePane::BrowseGBABios() @@ -499,6 +566,14 @@ void GameCubePane::LoadSettings() UpdateButton(slot); } + for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS) + { + SignalBlocking(m_memcard_paths[slot]) + ->setText(QString::fromStdString(Config::GetMemcardPath(slot, std::nullopt))); + SignalBlocking(m_agp_paths[slot]) + ->setText(QString::fromStdString(Config::Get(Config::GetInfoForAGPCartPath(slot)))); + } + #ifdef HAS_LIBMGBA // GBA Settings SignalBlocking(m_gba_threads)->setChecked(Config::Get(Config::MAIN_GBA_THREADS)); diff --git a/Source/Core/DolphinQt/Settings/GameCubePane.h b/Source/Core/DolphinQt/Settings/GameCubePane.h index 2bffc02bde..4ed1934e1c 100644 --- a/Source/Core/DolphinQt/Settings/GameCubePane.h +++ b/Source/Core/DolphinQt/Settings/GameCubePane.h @@ -14,8 +14,11 @@ class QCheckBox; class QComboBox; +class QHBoxLayout; +class QLabel; class QLineEdit; class QPushButton; +class QString; class GameCubePane : public QWidget { @@ -38,7 +41,9 @@ private: void OnConfigPressed(ExpansionInterface::Slot slot); void BrowseMemcard(ExpansionInterface::Slot slot); + bool SetMemcard(ExpansionInterface::Slot slot, const QString& filename); void BrowseAGPRom(ExpansionInterface::Slot slot); + void SetAGPRom(ExpansionInterface::Slot slot, const QString& filename); void BrowseGBABios(); void BrowseGBARom(size_t index); void SaveRomPathChanged(); @@ -50,6 +55,14 @@ private: Common::EnumMap m_slot_buttons; Common::EnumMap m_slot_combos; + Common::EnumMap m_memcard_path_layouts; + Common::EnumMap m_memcard_path_labels; + Common::EnumMap m_memcard_paths; + + Common::EnumMap m_agp_path_layouts; + Common::EnumMap m_agp_path_labels; + Common::EnumMap m_agp_paths; + QCheckBox* m_gba_threads; QCheckBox* m_gba_save_rom_path; QPushButton* m_gba_browse_bios; From 650f1726373250e2e3a91ccb4f934cdc4a68280b Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Mon, 11 Jul 2022 22:33:57 +0200 Subject: [PATCH 3/3] DolphinQt: Only show raw memory card path if it's not the default. --- Source/Core/Core/Config/MainSettings.cpp | 5 +++++ Source/Core/Core/Config/MainSettings.h | 1 + Source/Core/DolphinQt/Settings/GameCubePane.cpp | 8 ++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 85621d2f58..7ed4be23ad 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -644,4 +644,9 @@ std::string GetMemcardPath(std::string configured_filename, ExpansionInterface:: Config::GetDirectoryForRegion(Config::ToGameCubeRegion(used_region)), blocks_string, ext); } + +bool IsDefaultMemcardPathConfigured(ExpansionInterface::Slot slot) +{ + return Config::Get(GetInfoForMemcardPath(slot)).empty(); +} } // namespace Config diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index d8e682134b..197ae29688 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -350,4 +350,5 @@ std::string GetMemcardPath(ExpansionInterface::Slot slot, std::optional region, u16 size_mb = 0x80); +bool IsDefaultMemcardPathConfigured(ExpansionInterface::Slot slot); } // namespace Config diff --git a/Source/Core/DolphinQt/Settings/GameCubePane.cpp b/Source/Core/DolphinQt/Settings/GameCubePane.cpp index 0e6c19aef1..cc2b8fbe5f 100644 --- a/Source/Core/DolphinQt/Settings/GameCubePane.cpp +++ b/Source/Core/DolphinQt/Settings/GameCubePane.cpp @@ -300,14 +300,18 @@ void GameCubePane::UpdateButton(ExpansionInterface::Slot slot) { case ExpansionInterface::Slot::A: case ExpansionInterface::Slot::B: + { has_config = (device == ExpansionInterface::EXIDeviceType::MemoryCard || device == ExpansionInterface::EXIDeviceType::AGP || device == ExpansionInterface::EXIDeviceType::Microphone); - m_memcard_path_labels[slot]->setHidden(device != ExpansionInterface::EXIDeviceType::MemoryCard); - m_memcard_paths[slot]->setHidden(device != ExpansionInterface::EXIDeviceType::MemoryCard); + const bool hide_memory_card = device != ExpansionInterface::EXIDeviceType::MemoryCard || + Config::IsDefaultMemcardPathConfigured(slot); + m_memcard_path_labels[slot]->setHidden(hide_memory_card); + m_memcard_paths[slot]->setHidden(hide_memory_card); m_agp_path_labels[slot]->setHidden(device != ExpansionInterface::EXIDeviceType::AGP); m_agp_paths[slot]->setHidden(device != ExpansionInterface::EXIDeviceType::AGP); break; + } case ExpansionInterface::Slot::SP1: has_config = (device == ExpansionInterface::EXIDeviceType::Ethernet || device == ExpansionInterface::EXIDeviceType::EthernetXLink ||