Path: blob/master/src/duckstation-qt/biossettingswidget.cpp
4246 views
// SPDX-FileCopyrightText: 2019-2025 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"1718BIOSSettingsWidget::BIOSSettingsWidget(SettingsWindow* dialog, QWidget* parent) : QWidget(parent), m_dialog(dialog)19{20SettingsInterface* sif = dialog->getSettingsInterface();2122m_ui.setupUi(this);2324SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableTTYLogging, "BIOS", "TTYLogging", false);2526SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.pioDeviceType, "PIO", "DeviceType",27&Settings::ParsePIODeviceTypeName, &Settings::GetPIODeviceTypeModeName,28&Settings::GetPIODeviceTypeModeDisplayName,29Settings::DEFAULT_PIO_DEVICE_TYPE, PIODeviceType::MaxCount);30SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.pioImagePath, "PIO", "FlashImagePath");31SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pioSwitchActive, "PIO", "SwitchActive", true);32SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pioImageWrites, "PIO", "FlashImageWriteEnable", false);33connect(m_ui.pioDeviceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this,34&BIOSSettingsWidget::onPIODeviceTypeChanged);35connect(m_ui.pioImagePathBrowse, &QPushButton::clicked, this, &BIOSSettingsWidget::onPIOImagePathBrowseClicked);36onPIODeviceTypeChanged();3738connect(m_ui.imageNTSCJ, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {39if (m_dialog->isPerGameSettings() && index == 0)40{41m_dialog->removeSettingValue("BIOS", "PathNTSCJ");42}43else44{45m_dialog->setStringSettingValue("BIOS", "PathNTSCJ",46m_ui.imageNTSCJ->itemData(index).toString().toStdString().c_str());47}48});49connect(m_ui.imageNTSCU, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {50if (m_dialog->isPerGameSettings() && index == 0)51{52m_dialog->removeSettingValue("BIOS", "PathNTSCU");53}54else55{56m_dialog->setStringSettingValue("BIOS", "PathNTSCU",57m_ui.imageNTSCU->itemData(index).toString().toStdString().c_str());58}59});60connect(m_ui.imagePAL, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {61if (m_dialog->isPerGameSettings() && index == 0)62{63m_dialog->removeSettingValue("BIOS", "PathPAL");64}65else66{67m_dialog->setStringSettingValue("BIOS", "PathPAL",68m_ui.imagePAL->itemData(index).toString().toStdString().c_str());69}70});7172connect(m_ui.rescan, &QPushButton::clicked, this, &BIOSSettingsWidget::refreshList);7374if (!m_dialog->isPerGameSettings())75{76SettingWidgetBinder::BindWidgetToFolderSetting(77sif, m_ui.searchDirectory, m_ui.browseSearchDirectory, tr("Select BIOS Directory"), m_ui.searchDirectoryOpen,78m_ui.searchDirectoryReset, "BIOS", "SearchDirectory", Path::Combine(EmuFolders::DataRoot, "bios"));79connect(m_ui.searchDirectory, &QLineEdit::textChanged, this, &BIOSSettingsWidget::refreshList);80}81else82{83m_ui.mainLayout->removeWidget(m_ui.directoryGroupBox);84delete m_ui.directoryGroupBox;85m_ui.directoryGroupBox = nullptr;86m_ui.directoryGroupBoxLabel = nullptr;87m_ui.directoryGroupBoxLayout = nullptr;88m_ui.directoryGroupBoxHorizontalLayout = nullptr;89m_ui.searchDirectory = nullptr;90m_ui.browseSearchDirectory = nullptr;91}9293refreshList();9495dialog->registerWidgetHelp(m_ui.pioDeviceType, tr("Device Type"), tr("None"),96tr("Simulates a device plugged into the console's parallel port. Usually these are flash "97"cartridges, and require some sort of image dump to function."));98dialog->registerWidgetHelp(m_ui.pioImagePath, tr("Image Path"), tr("Empty"),99tr("Sets the path to the image used for flash cartridges."));100dialog->registerWidgetHelp(m_ui.pioSwitchActive, tr("Cartridge Switch On"), tr("Checked"),101tr("Simulates the position of the switch on the cartridge. Most cartridges require the "102"switch to be on for it to activate on startup."));103dialog->registerWidgetHelp(104m_ui.pioImageWrites, tr("Allow Image Writes"), tr("Unchecked"),105tr("Stores any images made to the cartridge's flash storage back to the host's file system. <strong>This will "106"overwrite your cartridge dump,</strong> you should ensure you have a backup first."));107dialog->registerWidgetHelp(m_ui.enableTTYLogging, tr("Enable TTY Logging"), tr("Unchecked"),108tr("Logs BIOS calls to printf(). Not all games contain debugging messages."));109}110111BIOSSettingsWidget::~BIOSSettingsWidget() = default;112113void BIOSSettingsWidget::refreshList()114{115auto images = BIOS::FindBIOSImagesInDirectory(EmuFolders::Bios.c_str());116populateDropDownForRegion(ConsoleRegion::NTSC_J, m_ui.imageNTSCJ, images, m_dialog->isPerGameSettings());117populateDropDownForRegion(ConsoleRegion::NTSC_U, m_ui.imageNTSCU, images, m_dialog->isPerGameSettings());118populateDropDownForRegion(ConsoleRegion::PAL, m_ui.imagePAL, images, m_dialog->isPerGameSettings());119120setDropDownValue(m_ui.imageNTSCJ, m_dialog->getStringValue("BIOS", "PathNTSCJ", std::nullopt),121m_dialog->isPerGameSettings());122setDropDownValue(m_ui.imageNTSCU, m_dialog->getStringValue("BIOS", "PathNTSCU", std::nullopt),123m_dialog->isPerGameSettings());124setDropDownValue(m_ui.imagePAL, m_dialog->getStringValue("BIOS", "PathPAL", std::nullopt),125m_dialog->isPerGameSettings());126}127128void BIOSSettingsWidget::populateDropDownForRegion(ConsoleRegion region, QComboBox* cb,129std::vector<std::pair<std::string, const BIOS::ImageInfo*>>& images,130bool per_game)131{132QSignalBlocker sb(cb);133cb->clear();134135if (per_game)136cb->addItem(QIcon(QStringLiteral(":/icons/system-search.png")), tr("Use Global Setting"));137138cb->addItem(QIcon(QStringLiteral(":/icons/system-search.png")), tr("Auto-Detect"));139140std::sort(images.begin(), images.end(), [region](const auto& left, const auto& right) {141const bool left_region_match = (left.second && left.second->region == region);142const bool right_region_match = (right.second && right.second->region == region);143if (left_region_match && !right_region_match)144return true;145else if (right_region_match && !left_region_match)146return false;147148return left.first < right.first;149});150151for (const auto& [name, info] : images)152{153QString name_str(QString::fromStdString(name));154cb->addItem(QtUtils::GetIconForRegion(info ? info->region : ConsoleRegion::Count),155QStringLiteral("%1 (%2)")156.arg(info ? QString(info->description) : qApp->translate("BIOSSettingsWidget", "Unknown"))157.arg(name_str),158QVariant(name_str));159}160}161162void BIOSSettingsWidget::setDropDownValue(QComboBox* cb, const std::optional<std::string>& name, bool per_game)163{164QSignalBlocker sb(cb);165166if (!name.has_value() || name->empty())167{168cb->setCurrentIndex((per_game && name.has_value()) ? 1 : 0);169return;170}171172QString qname(QString::fromStdString(name.value()));173for (int i = 1; i < cb->count(); i++)174{175if (cb->itemData(i) == qname)176{177cb->setCurrentIndex(i);178return;179}180}181182cb->addItem(qname, QVariant(qname));183cb->setCurrentIndex(cb->count() - 1);184}185186void BIOSSettingsWidget::onPIODeviceTypeChanged()187{188const PIODeviceType type =189Settings::ParsePIODeviceTypeName(190m_dialog191->getEffectiveStringValue("PIO", "DeviceType",192Settings::GetPIODeviceTypeModeName(Settings::DEFAULT_PIO_DEVICE_TYPE))193.c_str())194.value_or(Settings::DEFAULT_PIO_DEVICE_TYPE);195const bool has_image = (type == PIODeviceType::XplorerCart);196const bool has_switch = (type == PIODeviceType::XplorerCart);197m_ui.pioImagePathLabel->setEnabled(has_image);198m_ui.pioImagePath->setEnabled(has_image);199m_ui.pioImagePathBrowse->setEnabled(has_image);200m_ui.pioImageWrites->setEnabled(has_image);201m_ui.pioSwitchActive->setEnabled(has_switch);202}203204void BIOSSettingsWidget::onPIOImagePathBrowseClicked()205{206const QString path = QDir::toNativeSeparators(207QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("Select PIO Image"), m_ui.pioImagePath->text()));208if (path.isEmpty())209return;210211m_ui.pioImagePath->setText(path);212}213214215