diff options
| author | Jordan Woyak <jordan.woyak@gmail.com> | 2026-02-06 20:24:18 -0600 |
|---|---|---|
| committer | Jordan Woyak <jordan.woyak@gmail.com> | 2026-02-15 20:14:15 -0600 |
| commit | 7ab267269880b2007776b6b5e0090538bd577740 (patch) | |
| tree | c6cd55a2292d918bbb112a0ecf4561dbf16390a6 | |
| parent | 3e2b7fee46a8fcf623821b47b4fc4d50edeb65a8 (diff) | |
DolphinQt: Add user interface for Triforce IP address overrides.
| -rw-r--r-- | Source/Core/DolphinQt/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | Source/Core/DolphinQt/DolphinQt.vcxproj | 4 | ||||
| -rw-r--r-- | Source/Core/DolphinQt/Settings/GameCubePane.cpp | 14 | ||||
| -rw-r--r-- | Source/Core/DolphinQt/Settings/TriforceBaseboardSettingsDialog.cpp | 154 | ||||
| -rw-r--r-- | Source/Core/DolphinQt/Settings/TriforceBaseboardSettingsDialog.h | 26 |
5 files changed, 194 insertions, 6 deletions
diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 457ed8a157..0899ef5307 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -376,6 +376,8 @@ add_executable(dolphin-emu Settings/OnScreenDisplayPane.h Settings/PathPane.cpp Settings/PathPane.h + Settings/TriforceBaseboardSettingsDialog.cpp + Settings/TriforceBaseboardSettingsDialog.h Settings/USBDevicePicker.cpp Settings/USBDevicePicker.h Settings/WiiPane.cpp diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index 09f9163036..33741cb09c 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -223,6 +223,7 @@ <ClCompile Include="Settings\GeneralPane.cpp" /> <ClCompile Include="Settings\InterfacePane.cpp" /> <ClCompile Include="Settings\OnScreenDisplayPane.cpp" /> + <ClCompile Include="Settings\TriforceBaseboardSettingsDialog.cpp" /> <ClCompile Include="Settings\PathPane.cpp" /> <ClCompile Include="Settings\USBDevicePicker.cpp" /> <ClCompile Include="Settings\WiiPane.cpp" /> @@ -439,6 +440,7 @@ <QtMoc Include="Settings\GeneralPane.h" /> <QtMoc Include="Settings\InterfacePane.h" /> <QtMoc Include="Settings\PathPane.h" /> + <QtMoc Include="Settings\TriforceBaseboardSettingsDialog.h" /> <QtMoc Include="Settings\USBDevicePicker.h" /> <QtMoc Include="Settings\WiiPane.h" /> <QtMoc Include="SkylanderPortal\SkylanderPortalWindow.h" /> @@ -523,4 +525,4 @@ <Message Text="Copy: @(BinaryFiles) -> $(BinaryOutputDir)" Importance="High" /> <Copy SourceFiles="@(BinaryFiles)" DestinationFolder="$(BinaryOutputDir)" /> </Target> -</Project>
\ No newline at end of file +</Project> diff --git a/Source/Core/DolphinQt/Settings/GameCubePane.cpp b/Source/Core/DolphinQt/Settings/GameCubePane.cpp index 975130531e..692258edb5 100644 --- a/Source/Core/DolphinQt/Settings/GameCubePane.cpp +++ b/Source/Core/DolphinQt/Settings/GameCubePane.cpp @@ -50,6 +50,7 @@ #include "DolphinQt/QtUtils/SignalBlocking.h" #include "DolphinQt/Settings.h" #include "DolphinQt/Settings/BroadbandAdapterSettingsDialog.h" +#include "DolphinQt/Settings/TriforceBaseboardSettingsDialog.h" constexpr std::initializer_list<ExpansionInterface::Slot> GUI_SLOTS = { ExpansionInterface::Slot::A, ExpansionInterface::Slot::B, ExpansionInterface::Slot::SP1}; @@ -351,11 +352,12 @@ void GameCubePane::UpdateButton(ExpansionInterface::Slot slot) break; } case ExpansionInterface::Slot::SP1: - has_config = (device == ExpansionInterface::EXIDeviceType::Ethernet || - device == ExpansionInterface::EXIDeviceType::EthernetXLink || - device == ExpansionInterface::EXIDeviceType::EthernetTapServer || - device == ExpansionInterface::EXIDeviceType::EthernetBuiltIn || - device == ExpansionInterface::EXIDeviceType::ModemTapServer); + has_config = device == ExpansionInterface::EXIDeviceType::Ethernet || + device == ExpansionInterface::EXIDeviceType::EthernetXLink || + device == ExpansionInterface::EXIDeviceType::EthernetTapServer || + device == ExpansionInterface::EXIDeviceType::EthernetBuiltIn || + device == ExpansionInterface::EXIDeviceType::ModemTapServer || + device == ExpansionInterface::EXIDeviceType::Baseboard; break; case ExpansionInterface::Slot::SP2: has_config = false; @@ -421,6 +423,8 @@ void GameCubePane::OnConfigPressed(ExpansionInterface::Slot slot) } case ExpansionInterface::EXIDeviceType::Baseboard: { + TriforceBaseboardSettingsDialog dialog(this); + dialog.exec(); return; } default: diff --git a/Source/Core/DolphinQt/Settings/TriforceBaseboardSettingsDialog.cpp b/Source/Core/DolphinQt/Settings/TriforceBaseboardSettingsDialog.cpp new file mode 100644 index 0000000000..23d300dc43 --- /dev/null +++ b/Source/Core/DolphinQt/Settings/TriforceBaseboardSettingsDialog.cpp @@ -0,0 +1,154 @@ +// Copyright 2026 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "DolphinQt/Settings/TriforceBaseboardSettingsDialog.h" + +#include <QDialogButtonBox> +#include <QFormLayout> +#include <QGroupBox> +#include <QHeaderView> +#include <QLineEdit> +#include <QPushButton> +#include <QTableWidget> +#include <QVBoxLayout> + +#include <fmt/format.h> +#include <fmt/ranges.h> + +#include "Common/Logging/Log.h" + +#include "Core/Config/MainSettings.h" +#include "Core/HW/DVD/AMMediaboard.h" + +#include "DolphinQt/QtUtils/QtUtils.h" + +TriforceBaseboardSettingsDialog::TriforceBaseboardSettingsDialog(QWidget* parent) : QDialog{parent} +{ + setWindowTitle(tr("Triforce Baseboard")); + + connect(this, &TriforceBaseboardSettingsDialog::accepted, this, + &TriforceBaseboardSettingsDialog::SaveConfig); + + auto* const dialog_layout = new QVBoxLayout{this}; + + auto* const ip_override_group = new QGroupBox{tr("IP Address Overrides")}; + dialog_layout->addWidget(ip_override_group); + + auto* const ip_override_layout = new QFormLayout{ip_override_group}; + + m_bind_ip_edit = new QLineEdit; + ip_override_layout->addRow(tr("Bind IP: "), m_bind_ip_edit); + + m_ip_overrides_table = new QTableWidget; + ip_override_layout->addRow(tr("IP Overrides: "), m_ip_overrides_table); + + m_ip_overrides_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + + m_ip_overrides_table->setColumnCount(2); + m_ip_overrides_table->setHorizontalHeaderLabels({tr("Match"), tr("Replacement")}); + + m_ip_overrides_table->setEditTriggers(QAbstractItemView::DoubleClicked | + QAbstractItemView::EditKeyPressed); + + auto* const button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + dialog_layout->addWidget(button_box); + + auto* const load_default_button = new QPushButton(tr("Default")); + connect(load_default_button, &QPushButton::clicked, this, + &TriforceBaseboardSettingsDialog::LoadDefault); + + button_box->addButton(load_default_button, QDialogButtonBox::ActionRole); + + connect(button_box, &QDialogButtonBox::accepted, this, &TriforceBaseboardSettingsDialog::accept); + connect(button_box, &QDialogButtonBox::rejected, this, &TriforceBaseboardSettingsDialog::reject); + + connect(m_ip_overrides_table, &QTableWidget::itemChanged, this, [this](QTableWidgetItem* item) { + const int row_count = m_ip_overrides_table->rowCount(); + const bool is_last_row = item->row() == row_count - 1; + if (is_last_row) + { + if (!item->text().isEmpty()) + m_ip_overrides_table->insertRow(row_count); + } + else + { + // Just remove inner rows that have text erased. + // This UX could be less weird, but it's good enough for now. + if (item->text().isEmpty()) + m_ip_overrides_table->removeRow(item->row()); + } + }); + + LoadConfig(); + + QtUtils::AdjustSizeWithinScreen(this); +} + +void TriforceBaseboardSettingsDialog::LoadConfig() +{ + m_bind_ip_edit->setText(QString::fromUtf8(Config::Get(Config::MAIN_TRIFORCE_BIND_IP))); + + m_ip_overrides_table->setRowCount(0); + + // Add the final empty row. + m_ip_overrides_table->insertRow(0); + + int row = 0; + + const auto ip_overrides_str = Config::Get(Config::MAIN_TRIFORCE_IP_OVERRIDES); + for (auto&& ip_pair : ip_overrides_str | std::views::split(',')) + { + const auto ip_pair_str = std::string_view{ip_pair}; + const auto parts = AMMediaboard::ParseIPOverride(ip_pair_str); + if (!parts.has_value()) + { + ERROR_LOG_FMT(COMMON, "Bad IP pair string: {}", ip_pair_str); + continue; + } + + m_ip_overrides_table->insertRow(row); + + m_ip_overrides_table->setItem(row, 0, new QTableWidgetItem(QString::fromUtf8(parts->first))); + m_ip_overrides_table->setItem(row, 1, new QTableWidgetItem(QString::fromUtf8(parts->second))); + + ++row; + } +} + +void TriforceBaseboardSettingsDialog::SaveConfig() +{ + Config::SetBaseOrCurrent(Config::MAIN_TRIFORCE_BIND_IP, m_bind_ip_edit->text().toStdString()); + + // Ignore our empty row. + const int row_count = m_ip_overrides_table->rowCount() - 1; + + std::vector<std::string> replacements(row_count); + for (int row = 0; row < row_count; ++row) + { + // Skip incomplete rows. + if (m_ip_overrides_table->item(row, 0) == nullptr || + m_ip_overrides_table->item(row, 1) == nullptr) + { + continue; + } + + replacements[row] = + std::string(StripWhitespace(m_ip_overrides_table->item(row, 0)->text().toStdString())) + + "=" + + std::string(StripWhitespace(m_ip_overrides_table->item(row, 1)->text().toStdString())); + } + + // TODO: Ideally we'd remove duplicates based on the first IP. + + Config::SetBaseOrCurrent(Config::MAIN_TRIFORCE_IP_OVERRIDES, + fmt::format("{}", fmt::join(replacements, ","))); +} + +void TriforceBaseboardSettingsDialog::LoadDefault() +{ + // This alters the config before "OK" is pressed. Bad UX.. + Config::SetBaseOrCurrent(Config::MAIN_TRIFORCE_BIND_IP, Config::DefaultState{}); + Config::SetBaseOrCurrent(Config::MAIN_TRIFORCE_IP_OVERRIDES, Config::DefaultState{}); + + LoadConfig(); +} diff --git a/Source/Core/DolphinQt/Settings/TriforceBaseboardSettingsDialog.h b/Source/Core/DolphinQt/Settings/TriforceBaseboardSettingsDialog.h new file mode 100644 index 0000000000..e472739f71 --- /dev/null +++ b/Source/Core/DolphinQt/Settings/TriforceBaseboardSettingsDialog.h @@ -0,0 +1,26 @@ +// Copyright 2026 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <QDialog> + +class QLineEdit; +class QTableWidget; + +class TriforceBaseboardSettingsDialog final : public QDialog +{ + Q_OBJECT + +public: + explicit TriforceBaseboardSettingsDialog(QWidget* parent); + +private: + void LoadConfig(); + void SaveConfig(); + + void LoadDefault(); + + QLineEdit* m_bind_ip_edit; + QTableWidget* m_ip_overrides_table; +}; |
