Path: blob/master/src/duckstation-qt/biossettingswidget.cpp
7528 views
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <[email protected]>1// SPDX-License-Identifier: CC-BY-NC-ND-4.023#include "biossettingswidget.h"4#include "qthost.h"5#include "qtutils.h"6#include "settingswindow.h"7#include "settingwidgetbinder.h"89#include "core/bios.h"10#include "core/settings.h"1112#include <QtCore/QDir>13#include <QtWidgets/QFileDialog>14#include <algorithm>1516#include "moc_biossettingswidget.cpp"1718using namespace Qt::StringLiterals;1920BIOSSettingsWidget::BIOSSettingsWidget(SettingsWindow* dialog, QWidget* parent) : QWidget(parent), m_dialog(dialog)21{22SettingsInterface* sif = dialog->getSettingsInterface();2324m_ui.setupUi(this);2526SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableTTYLogging, "BIOS", "TTYLogging", false);2728SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.pioDeviceType, "PIO", "DeviceType",29&Settings::ParsePIODeviceTypeName, &Settings::GetPIODeviceTypeModeName,30&Settings::GetPIODeviceTypeModeDisplayName,31Settings::DEFAULT_PIO_DEVICE_TYPE, PIODeviceType::MaxCount);32SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.pioImagePath, "PIO", "FlashImagePath");33SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pioSwitchActive, "PIO", "SwitchActive", true);34SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pioImageWrites, "PIO", "FlashImageWriteEnable", false);35connect(m_ui.pioDeviceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this,36&BIOSSettingsWidget::onPIODeviceTypeChanged);37connect(m_ui.pioImagePathBrowse, &QPushButton::clicked, this, &BIOSSettingsWidget::onPIOImagePathBrowseClicked);38onPIODeviceTypeChanged();3940connect(m_ui.imageNTSCJ, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {41if (m_dialog->isPerGameSettings() && index == 0)42{43m_dialog->removeSettingValue("BIOS", "PathNTSCJ");44}45else46{47m_dialog->setStringSettingValue("BIOS", "PathNTSCJ",48m_ui.imageNTSCJ->itemData(index).toString().toStdString().c_str());49}50});51connect(m_ui.imageNTSCU, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {52if (m_dialog->isPerGameSettings() && index == 0)53{54m_dialog->removeSettingValue("BIOS", "PathNTSCU");55}56else57{58m_dialog->setStringSettingValue("BIOS", "PathNTSCU",59m_ui.imageNTSCU->itemData(index).toString().toStdString().c_str());60}61});62connect(m_ui.imagePAL, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {63if (m_dialog->isPerGameSettings() && index == 0)64{65m_dialog->removeSettingValue("BIOS", "PathPAL");66}67else68{69m_dialog->setStringSettingValue("BIOS", "PathPAL",70m_ui.imagePAL->itemData(index).toString().toStdString().c_str());71}72});7374connect(m_ui.rescan, &QPushButton::clicked, this, &BIOSSettingsWidget::refreshList);7576if (!m_dialog->isPerGameSettings())77{78SettingWidgetBinder::BindWidgetToFolderSetting(79sif, m_ui.searchDirectory, m_ui.browseSearchDirectory, tr("Select BIOS Directory"), m_ui.searchDirectoryOpen,80m_ui.searchDirectoryReset, "BIOS", "SearchDirectory", Path::Combine(EmuFolders::DataRoot, "bios"));81connect(m_ui.searchDirectory, &QLineEdit::textChanged, this, &BIOSSettingsWidget::refreshList);82}83else84{85m_ui.mainLayout->removeWidget(m_ui.directoryGroupBox);86delete m_ui.directoryGroupBox;87m_ui.directoryGroupBox = nullptr;88m_ui.directoryGroupBoxLabel = nullptr;89m_ui.directoryGroupBoxLayout = nullptr;90m_ui.directoryGroupBoxHorizontalLayout = nullptr;91m_ui.searchDirectory = nullptr;92m_ui.browseSearchDirectory = nullptr;93}9495refreshList();9697dialog->registerWidgetHelp(m_ui.pioDeviceType, tr("Device Type"), tr("None"),98tr("Simulates a device plugged into the console's parallel port. Usually these are flash "99"cartridges, and require some sort of image dump to function."));100dialog->registerWidgetHelp(m_ui.pioImagePath, tr("Image Path"), tr("Empty"),101tr("Sets the path to the image used for flash cartridges."));102dialog->registerWidgetHelp(m_ui.pioSwitchActive, tr("Cartridge Switch On"), tr("Checked"),103tr("Simulates the position of the switch on the cartridge. Most cartridges require the "104"switch to be on for it to activate on startup."));105dialog->registerWidgetHelp(106m_ui.pioImageWrites, tr("Allow Image Writes"), tr("Unchecked"),107tr("Stores any images made to the cartridge's flash storage back to the host's file system. <strong>This will "108"overwrite your cartridge dump,</strong> you should ensure you have a backup first."));109dialog->registerWidgetHelp(m_ui.enableTTYLogging, tr("Enable TTY Logging"), tr("Unchecked"),110tr("Logs BIOS calls to printf(). Not all games contain debugging messages."));111}112113BIOSSettingsWidget::~BIOSSettingsWidget() = default;114115void BIOSSettingsWidget::refreshList()116{117auto images = BIOS::FindBIOSImagesInDirectory(EmuFolders::Bios.c_str());118populateDropDownForRegion(ConsoleRegion::NTSC_J, m_ui.imageNTSCJ, images, m_dialog->isPerGameSettings());119populateDropDownForRegion(ConsoleRegion::NTSC_U, m_ui.imageNTSCU, images, m_dialog->isPerGameSettings());120populateDropDownForRegion(ConsoleRegion::PAL, m_ui.imagePAL, images, m_dialog->isPerGameSettings());121122setDropDownValue(m_ui.imageNTSCJ, m_dialog->getStringValue("BIOS", "PathNTSCJ", std::nullopt),123m_dialog->isPerGameSettings());124setDropDownValue(m_ui.imageNTSCU, m_dialog->getStringValue("BIOS", "PathNTSCU", std::nullopt),125m_dialog->isPerGameSettings());126setDropDownValue(m_ui.imagePAL, m_dialog->getStringValue("BIOS", "PathPAL", std::nullopt),127m_dialog->isPerGameSettings());128}129130void BIOSSettingsWidget::populateDropDownForRegion(ConsoleRegion region, QComboBox* cb,131std::vector<std::pair<std::string, const BIOS::ImageInfo*>>& images,132bool per_game)133{134QSignalBlocker sb(cb);135cb->clear();136137if (per_game)138cb->addItem(QIcon(":/icons/system-search.png"_L1), tr("Use Global Setting"));139140cb->addItem(QIcon(":/icons/system-search.png"_L1), tr("Auto-Detect"));141142std::sort(images.begin(), images.end(), [region](const auto& left, const auto& right) {143const bool left_region_match = (left.second && left.second->region == region);144const bool right_region_match = (right.second && right.second->region == region);145if (left_region_match && !right_region_match)146return true;147else if (right_region_match && !left_region_match)148return false;149150return left.first < right.first;151});152153for (const auto& [name, info] : images)154{155QString name_str(QString::fromStdString(name));156cb->addItem(QtUtils::GetIconForRegion(info ? info->region : ConsoleRegion::Count),157QStringLiteral("%1 (%2)")158.arg(info ? QString(info->description) : qApp->translate("BIOSSettingsWidget", "Unknown"))159.arg(name_str),160QVariant(name_str));161}162}163164void BIOSSettingsWidget::setDropDownValue(QComboBox* cb, const std::optional<std::string>& name, bool per_game)165{166QSignalBlocker sb(cb);167168if (!name.has_value() || name->empty())169{170cb->setCurrentIndex((per_game && name.has_value()) ? 1 : 0);171return;172}173174QString qname(QString::fromStdString(name.value()));175for (int i = 1; i < cb->count(); i++)176{177if (cb->itemData(i) == qname)178{179cb->setCurrentIndex(i);180return;181}182}183184cb->addItem(QIcon::fromTheme("close-line"_L1), tr("%1 (Missing)").arg(qname), QVariant(qname));185cb->setCurrentIndex(cb->count() - 1);186}187188void BIOSSettingsWidget::onPIODeviceTypeChanged()189{190const PIODeviceType type =191Settings::ParsePIODeviceTypeName(192m_dialog193->getEffectiveStringValue("PIO", "DeviceType",194Settings::GetPIODeviceTypeModeName(Settings::DEFAULT_PIO_DEVICE_TYPE))195.c_str())196.value_or(Settings::DEFAULT_PIO_DEVICE_TYPE);197const bool has_image = (type == PIODeviceType::XplorerCart);198const bool has_switch = (type == PIODeviceType::XplorerCart);199m_ui.pioImagePathLabel->setEnabled(has_image);200m_ui.pioImagePath->setEnabled(has_image);201m_ui.pioImagePathBrowse->setEnabled(has_image);202m_ui.pioImageWrites->setEnabled(has_image);203m_ui.pioSwitchActive->setEnabled(has_switch);204}205206void BIOSSettingsWidget::onPIOImagePathBrowseClicked()207{208const QString path =209QDir::toNativeSeparators(QFileDialog::getOpenFileName(this, tr("Select PIO Image"), m_ui.pioImagePath->text()));210if (path.isEmpty())211return;212213m_ui.pioImagePath->setText(path);214}215216217