2018-01-03 17:41:31 -07:00
|
|
|
// Copyright 2018 Dolphin Emulator Project
|
2021-07-04 19:22:19 -06:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2018-01-03 17:41:31 -07:00
|
|
|
|
2018-07-06 16:40:15 -06:00
|
|
|
#include "DolphinQt/Settings/GameCubePane.h"
|
2018-01-03 17:41:31 -07:00
|
|
|
|
|
|
|
#include <QCheckBox>
|
|
|
|
#include <QComboBox>
|
|
|
|
#include <QFileDialog>
|
|
|
|
#include <QFileInfo>
|
2021-09-08 14:08:43 -06:00
|
|
|
#include <QFormLayout>
|
2018-01-03 17:41:31 -07:00
|
|
|
#include <QGridLayout>
|
|
|
|
#include <QGroupBox>
|
2019-01-24 13:08:21 -07:00
|
|
|
#include <QInputDialog>
|
2018-01-03 17:41:31 -07:00
|
|
|
#include <QLabel>
|
2021-07-04 04:53:53 -06:00
|
|
|
#include <QLineEdit>
|
2018-01-03 17:41:31 -07:00
|
|
|
#include <QPushButton>
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
2019-01-24 13:08:21 -07:00
|
|
|
#include <utility>
|
|
|
|
|
2018-01-03 17:41:31 -07:00
|
|
|
#include "Common/CommonPaths.h"
|
2018-07-04 15:01:50 -06:00
|
|
|
#include "Common/Config/Config.h"
|
2018-01-03 17:41:31 -07:00
|
|
|
#include "Common/FileUtil.h"
|
2021-07-04 04:53:53 -06:00
|
|
|
#include "Common/MsgHandler.h"
|
2018-05-27 19:48:04 -06:00
|
|
|
|
2018-07-04 15:01:50 -06:00
|
|
|
#include "Core/Config/MainSettings.h"
|
2018-01-03 17:41:31 -07:00
|
|
|
#include "Core/ConfigManager.h"
|
|
|
|
#include "Core/Core.h"
|
|
|
|
#include "Core/HW/EXI/EXI.h"
|
|
|
|
#include "Core/HW/GCMemcard/GCMemcard.h"
|
2021-07-04 04:53:53 -06:00
|
|
|
#include "Core/NetPlayServer.h"
|
2018-05-27 19:48:04 -06:00
|
|
|
|
2018-07-06 16:40:15 -06:00
|
|
|
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
2019-08-14 20:08:20 -06:00
|
|
|
#include "DolphinQt/GCMemcardManager.h"
|
2021-10-09 20:28:59 -06:00
|
|
|
#include "DolphinQt/QtUtils/DolphinFileDialog.h"
|
2019-03-04 12:49:00 -07:00
|
|
|
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
2021-07-04 04:53:53 -06:00
|
|
|
#include "DolphinQt/Settings.h"
|
2021-09-08 14:08:43 -06:00
|
|
|
#include "DolphinQt/Settings/BroadbandAdapterSettingsDialog.h"
|
2018-01-03 17:41:31 -07:00
|
|
|
|
2019-01-24 13:08:21 -07:00
|
|
|
enum
|
2018-01-25 12:39:03 -07:00
|
|
|
{
|
2019-01-24 13:08:21 -07:00
|
|
|
SLOT_A_INDEX,
|
|
|
|
SLOT_B_INDEX,
|
|
|
|
SLOT_SP1_INDEX,
|
|
|
|
SLOT_COUNT
|
2018-01-25 12:39:03 -07:00
|
|
|
};
|
2018-01-03 17:41:31 -07:00
|
|
|
|
|
|
|
GameCubePane::GameCubePane()
|
|
|
|
{
|
|
|
|
CreateWidgets();
|
|
|
|
LoadSettings();
|
2018-01-25 12:39:03 -07:00
|
|
|
ConnectWidgets();
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void GameCubePane::CreateWidgets()
|
|
|
|
{
|
2020-08-17 01:07:38 -06:00
|
|
|
using ExpansionInterface::EXIDeviceType;
|
|
|
|
|
2019-01-24 13:08:21 -07:00
|
|
|
QVBoxLayout* layout = new QVBoxLayout(this);
|
2018-01-03 17:41:31 -07:00
|
|
|
|
|
|
|
// IPL Settings
|
2019-01-24 13:08:21 -07:00
|
|
|
QGroupBox* ipl_box = new QGroupBox(tr("IPL Settings"), this);
|
2021-09-08 14:08:43 -06:00
|
|
|
QVBoxLayout* ipl_box_layout = new QVBoxLayout(ipl_box);
|
|
|
|
ipl_box->setLayout(ipl_box_layout);
|
2018-01-03 17:41:31 -07:00
|
|
|
|
2019-01-24 13:08:21 -07:00
|
|
|
m_skip_main_menu = new QCheckBox(tr("Skip Main Menu"), ipl_box);
|
2021-09-08 14:08:43 -06:00
|
|
|
ipl_box_layout->addWidget(m_skip_main_menu);
|
|
|
|
|
|
|
|
QFormLayout* ipl_language_layout = new QFormLayout;
|
|
|
|
ipl_language_layout->setFormAlignment(Qt::AlignLeft | Qt::AlignTop);
|
|
|
|
ipl_language_layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
|
|
|
ipl_box_layout->addLayout(ipl_language_layout);
|
|
|
|
|
2019-01-24 13:08:21 -07:00
|
|
|
m_language_combo = new QComboBox(ipl_box);
|
|
|
|
m_language_combo->setCurrentIndex(-1);
|
2021-09-08 14:08:43 -06:00
|
|
|
ipl_language_layout->addRow(tr("System Language:"), m_language_combo);
|
2018-01-03 17:41:31 -07:00
|
|
|
|
|
|
|
// Add languages
|
2019-01-24 13:08:21 -07:00
|
|
|
for (const auto& entry : {std::make_pair(tr("English"), 0), std::make_pair(tr("German"), 1),
|
|
|
|
std::make_pair(tr("French"), 2), std::make_pair(tr("Spanish"), 3),
|
|
|
|
std::make_pair(tr("Italian"), 4), std::make_pair(tr("Dutch"), 5)})
|
|
|
|
{
|
|
|
|
m_language_combo->addItem(entry.first, entry.second);
|
|
|
|
}
|
2018-01-03 17:41:31 -07:00
|
|
|
|
|
|
|
// Device Settings
|
2019-01-24 13:08:21 -07:00
|
|
|
QGroupBox* device_box = new QGroupBox(tr("Device Settings"), this);
|
|
|
|
QGridLayout* device_layout = new QGridLayout(device_box);
|
2018-01-03 17:41:31 -07:00
|
|
|
device_box->setLayout(device_layout);
|
|
|
|
|
2019-01-24 13:08:21 -07:00
|
|
|
for (int i = 0; i < SLOT_COUNT; i++)
|
|
|
|
{
|
|
|
|
m_slot_combos[i] = new QComboBox(device_box);
|
2021-09-08 14:08:43 -06:00
|
|
|
m_slot_combos[i]->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
2019-01-24 13:08:21 -07:00
|
|
|
m_slot_buttons[i] = new QPushButton(tr("..."), device_box);
|
|
|
|
m_slot_buttons[i]->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
|
|
|
}
|
2018-01-03 17:41:31 -07:00
|
|
|
|
|
|
|
// Add slot devices
|
2020-08-17 01:07:38 -06:00
|
|
|
for (const auto& entry : {std::make_pair(tr("<Nothing>"), EXIDeviceType::None),
|
|
|
|
std::make_pair(tr("Dummy"), EXIDeviceType::Dummy),
|
|
|
|
std::make_pair(tr("Memory Card"), EXIDeviceType::MemoryCard),
|
|
|
|
std::make_pair(tr("GCI Folder"), EXIDeviceType::MemoryCardFolder),
|
|
|
|
std::make_pair(tr("USB Gecko"), EXIDeviceType::Gecko),
|
|
|
|
std::make_pair(tr("Advance Game Port"), EXIDeviceType::AGP),
|
|
|
|
std::make_pair(tr("Microphone"), EXIDeviceType::Microphone)})
|
2018-01-03 17:41:31 -07:00
|
|
|
{
|
2020-08-17 01:07:38 -06:00
|
|
|
m_slot_combos[0]->addItem(entry.first, static_cast<int>(entry.second));
|
|
|
|
m_slot_combos[1]->addItem(entry.first, static_cast<int>(entry.second));
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add SP1 devices
|
2020-08-17 01:07:38 -06:00
|
|
|
std::vector<std::pair<QString, EXIDeviceType>> sp1Entries{
|
|
|
|
std::make_pair(tr("<Nothing>"), EXIDeviceType::None),
|
|
|
|
std::make_pair(tr("Dummy"), EXIDeviceType::Dummy),
|
|
|
|
std::make_pair(tr("Broadband Adapter (TAP)"), EXIDeviceType::Ethernet),
|
|
|
|
std::make_pair(tr("Broadband Adapter (XLink Kai)"), EXIDeviceType::EthernetXLink)};
|
2020-09-27 14:15:14 -06:00
|
|
|
#if defined(__APPLE__)
|
|
|
|
sp1Entries.emplace_back(std::make_pair(tr("Broadband Adapter (tapserver)"),
|
2020-08-17 01:07:38 -06:00
|
|
|
ExpansionInterface::EXIDeviceType::EthernetTapServer));
|
2020-09-27 14:15:14 -06:00
|
|
|
#endif
|
|
|
|
for (const auto& entry : sp1Entries)
|
2018-01-03 17:41:31 -07:00
|
|
|
{
|
2020-08-17 01:07:38 -06:00
|
|
|
m_slot_combos[2]->addItem(entry.first, static_cast<int>(entry.second));
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
device_layout->addWidget(new QLabel(tr("Slot A:")), 0, 0);
|
|
|
|
device_layout->addWidget(m_slot_combos[0], 0, 1);
|
|
|
|
device_layout->addWidget(m_slot_buttons[0], 0, 2);
|
|
|
|
device_layout->addWidget(new QLabel(tr("Slot B:")), 1, 0);
|
|
|
|
device_layout->addWidget(m_slot_combos[1], 1, 1);
|
|
|
|
device_layout->addWidget(m_slot_buttons[1], 1, 2);
|
|
|
|
device_layout->addWidget(new QLabel(tr("SP1:")), 2, 0);
|
|
|
|
device_layout->addWidget(m_slot_combos[2], 2, 1);
|
2019-01-24 13:08:21 -07:00
|
|
|
device_layout->addWidget(m_slot_buttons[2], 2, 2);
|
2018-01-03 17:41:31 -07:00
|
|
|
|
2021-07-04 04:53:53 -06:00
|
|
|
#ifdef HAS_LIBMGBA
|
|
|
|
// GBA Settings
|
|
|
|
auto* gba_box = new QGroupBox(tr("GBA Settings"), this);
|
|
|
|
auto* gba_layout = new QGridLayout(gba_box);
|
|
|
|
gba_box->setLayout(gba_layout);
|
|
|
|
int gba_row = 0;
|
|
|
|
|
|
|
|
m_gba_threads = new QCheckBox(tr("Run GBA Cores in Dedicated Threads"));
|
|
|
|
gba_layout->addWidget(m_gba_threads, gba_row, 0, 1, -1);
|
|
|
|
gba_row++;
|
|
|
|
|
|
|
|
m_gba_bios_edit = new QLineEdit();
|
|
|
|
m_gba_browse_bios = new QPushButton(QStringLiteral("..."));
|
|
|
|
gba_layout->addWidget(new QLabel(tr("BIOS:")), gba_row, 0);
|
|
|
|
gba_layout->addWidget(m_gba_bios_edit, gba_row, 1);
|
|
|
|
gba_layout->addWidget(m_gba_browse_bios, gba_row, 2);
|
|
|
|
gba_row++;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < m_gba_rom_edits.size(); ++i)
|
|
|
|
{
|
|
|
|
m_gba_rom_edits[i] = new QLineEdit();
|
|
|
|
m_gba_browse_roms[i] = new QPushButton(QStringLiteral("..."));
|
|
|
|
gba_layout->addWidget(new QLabel(tr("Port %1 ROM:").arg(i + 1)), gba_row, 0);
|
|
|
|
gba_layout->addWidget(m_gba_rom_edits[i], gba_row, 1);
|
|
|
|
gba_layout->addWidget(m_gba_browse_roms[i], gba_row, 2);
|
|
|
|
gba_row++;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_gba_save_rom_path = new QCheckBox(tr("Save in Same Directory as the ROM"));
|
|
|
|
gba_layout->addWidget(m_gba_save_rom_path, gba_row, 0, 1, -1);
|
|
|
|
gba_row++;
|
|
|
|
|
|
|
|
m_gba_saves_edit = new QLineEdit();
|
|
|
|
m_gba_browse_saves = new QPushButton(QStringLiteral("..."));
|
|
|
|
gba_layout->addWidget(new QLabel(tr("Saves:")), gba_row, 0);
|
|
|
|
gba_layout->addWidget(m_gba_saves_edit, gba_row, 1);
|
|
|
|
gba_layout->addWidget(m_gba_browse_saves, gba_row, 2);
|
|
|
|
gba_row++;
|
|
|
|
#endif
|
|
|
|
|
2018-01-03 17:41:31 -07:00
|
|
|
layout->addWidget(ipl_box);
|
|
|
|
layout->addWidget(device_box);
|
2021-07-04 04:53:53 -06:00
|
|
|
#ifdef HAS_LIBMGBA
|
|
|
|
layout->addWidget(gba_box);
|
|
|
|
#endif
|
2018-01-03 17:41:31 -07:00
|
|
|
|
2018-03-24 11:18:17 -06:00
|
|
|
layout->addStretch();
|
|
|
|
|
2018-01-03 17:41:31 -07:00
|
|
|
setLayout(layout);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameCubePane::ConnectWidgets()
|
|
|
|
{
|
|
|
|
// IPL Settings
|
|
|
|
connect(m_skip_main_menu, &QCheckBox::stateChanged, this, &GameCubePane::SaveSettings);
|
2019-07-30 07:35:46 -06:00
|
|
|
connect(m_language_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
2019-01-24 13:08:21 -07:00
|
|
|
&GameCubePane::SaveSettings);
|
2018-01-03 17:41:31 -07:00
|
|
|
|
|
|
|
// Device Settings
|
|
|
|
for (int i = 0; i < SLOT_COUNT; i++)
|
|
|
|
{
|
2019-07-30 07:35:46 -06:00
|
|
|
connect(m_slot_combos[i], qOverload<int>(&QComboBox::currentIndexChanged), this,
|
2019-01-24 13:08:21 -07:00
|
|
|
[this, i] { UpdateButton(i); });
|
2019-07-30 07:35:46 -06:00
|
|
|
connect(m_slot_combos[i], qOverload<int>(&QComboBox::currentIndexChanged), this,
|
2018-01-03 17:41:31 -07:00
|
|
|
&GameCubePane::SaveSettings);
|
2019-07-23 16:18:58 -06:00
|
|
|
connect(m_slot_buttons[i], &QPushButton::clicked, [this, i] { OnConfigPressed(i); });
|
2019-01-24 13:08:21 -07:00
|
|
|
}
|
2021-07-04 04:53:53 -06:00
|
|
|
|
|
|
|
#ifdef HAS_LIBMGBA
|
|
|
|
// GBA Settings
|
|
|
|
connect(m_gba_threads, &QCheckBox::stateChanged, this, &GameCubePane::SaveSettings);
|
|
|
|
connect(m_gba_bios_edit, &QLineEdit::editingFinished, this, &GameCubePane::SaveSettings);
|
|
|
|
connect(m_gba_browse_bios, &QPushButton::clicked, this, &GameCubePane::BrowseGBABios);
|
|
|
|
connect(m_gba_save_rom_path, &QCheckBox::stateChanged, this, &GameCubePane::SaveRomPathChanged);
|
|
|
|
connect(m_gba_saves_edit, &QLineEdit::editingFinished, this, &GameCubePane::SaveSettings);
|
|
|
|
connect(m_gba_browse_saves, &QPushButton::clicked, this, &GameCubePane::BrowseGBASaves);
|
|
|
|
for (size_t i = 0; i < m_gba_browse_roms.size(); ++i)
|
|
|
|
{
|
|
|
|
connect(m_gba_rom_edits[i], &QLineEdit::editingFinished, this, &GameCubePane::SaveSettings);
|
|
|
|
connect(m_gba_browse_roms[i], &QPushButton::clicked, this, [this, i] { BrowseGBARom(i); });
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Emulation State
|
|
|
|
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
|
|
|
&GameCubePane::OnEmulationStateChanged);
|
|
|
|
OnEmulationStateChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameCubePane::OnEmulationStateChanged()
|
|
|
|
{
|
|
|
|
#ifdef HAS_LIBMGBA
|
|
|
|
bool gba_enabled = !NetPlay::IsNetPlayRunning();
|
|
|
|
m_gba_threads->setEnabled(gba_enabled);
|
|
|
|
m_gba_bios_edit->setEnabled(gba_enabled);
|
|
|
|
m_gba_browse_bios->setEnabled(gba_enabled);
|
|
|
|
m_gba_save_rom_path->setEnabled(gba_enabled);
|
|
|
|
m_gba_saves_edit->setEnabled(gba_enabled);
|
|
|
|
m_gba_browse_saves->setEnabled(gba_enabled);
|
|
|
|
for (size_t i = 0; i < m_gba_browse_roms.size(); ++i)
|
|
|
|
{
|
|
|
|
m_gba_rom_edits[i]->setEnabled(gba_enabled);
|
|
|
|
m_gba_browse_roms[i]->setEnabled(gba_enabled);
|
|
|
|
}
|
|
|
|
#endif
|
2019-01-24 13:08:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void GameCubePane::UpdateButton(int slot)
|
|
|
|
{
|
2020-08-17 01:07:38 -06:00
|
|
|
const auto device =
|
|
|
|
static_cast<ExpansionInterface::EXIDeviceType>(m_slot_combos[slot]->currentData().toInt());
|
2019-01-24 13:08:21 -07:00
|
|
|
bool has_config = false;
|
|
|
|
|
|
|
|
switch (slot)
|
|
|
|
{
|
|
|
|
case SLOT_A_INDEX:
|
|
|
|
case SLOT_B_INDEX:
|
2020-08-17 01:07:38 -06:00
|
|
|
has_config = (device == ExpansionInterface::EXIDeviceType::MemoryCard ||
|
|
|
|
device == ExpansionInterface::EXIDeviceType::AGP ||
|
|
|
|
device == ExpansionInterface::EXIDeviceType::Microphone);
|
2019-01-24 13:08:21 -07:00
|
|
|
break;
|
|
|
|
case SLOT_SP1_INDEX:
|
2020-08-17 01:07:38 -06:00
|
|
|
has_config = (device == ExpansionInterface::EXIDeviceType::Ethernet ||
|
|
|
|
device == ExpansionInterface::EXIDeviceType::EthernetXLink);
|
2019-01-24 13:08:21 -07:00
|
|
|
break;
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
2019-01-24 13:08:21 -07:00
|
|
|
|
|
|
|
m_slot_buttons[slot]->setEnabled(has_config);
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void GameCubePane::OnConfigPressed(int slot)
|
|
|
|
{
|
|
|
|
QString filter;
|
|
|
|
bool memcard = false;
|
|
|
|
|
2020-08-17 01:07:38 -06:00
|
|
|
const ExpansionInterface::EXIDeviceType device =
|
|
|
|
static_cast<ExpansionInterface::EXIDeviceType>(m_slot_combos[slot]->currentData().toInt());
|
|
|
|
|
|
|
|
switch (device)
|
2018-01-03 17:41:31 -07:00
|
|
|
{
|
2020-08-17 01:07:38 -06:00
|
|
|
case ExpansionInterface::EXIDeviceType::MemoryCard:
|
2018-01-30 02:23:57 -07:00
|
|
|
filter = tr("GameCube Memory Cards (*.raw *.gcp)");
|
2018-01-03 17:41:31 -07:00
|
|
|
memcard = true;
|
|
|
|
break;
|
2020-08-17 01:07:38 -06:00
|
|
|
case ExpansionInterface::EXIDeviceType::AGP:
|
2018-01-03 17:41:31 -07:00
|
|
|
filter = tr("Game Boy Advance Carts (*.gba)");
|
|
|
|
break;
|
2020-08-17 01:07:38 -06:00
|
|
|
case ExpansionInterface::EXIDeviceType::Microphone:
|
2018-01-03 17:41:31 -07:00
|
|
|
MappingWindow(this, MappingWindow::Type::MAPPING_GC_MICROPHONE, slot).exec();
|
|
|
|
return;
|
2020-08-17 01:07:38 -06:00
|
|
|
case ExpansionInterface::EXIDeviceType::Ethernet:
|
2019-01-24 13:08:21 -07:00
|
|
|
{
|
2021-09-08 14:08:43 -06:00
|
|
|
BroadbandAdapterSettingsDialog(this, BroadbandAdapterSettingsDialog::Type::Ethernet).exec();
|
2019-01-24 13:08:21 -07:00
|
|
|
return;
|
|
|
|
}
|
2020-08-17 01:07:38 -06:00
|
|
|
case ExpansionInterface::EXIDeviceType::EthernetXLink:
|
2020-06-07 21:25:45 -06:00
|
|
|
{
|
2021-09-08 14:08:43 -06:00
|
|
|
BroadbandAdapterSettingsDialog(this, BroadbandAdapterSettingsDialog::Type::XLinkKai).exec();
|
2019-01-24 13:08:21 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
default:
|
2020-08-17 01:07:38 -06:00
|
|
|
PanicAlertFmt("Unknown settings pressed for {}", device);
|
|
|
|
return;
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
|
2021-10-09 20:28:59 -06:00
|
|
|
QString filename = DolphinFileDialog::getSaveFileName(
|
2018-06-25 22:37:08 -06:00
|
|
|
this, tr("Choose a file to open"), QString::fromStdString(File::GetUserPath(D_GCUSER_IDX)),
|
|
|
|
filter, 0, QFileDialog::DontConfirmOverwrite);
|
2018-01-03 17:41:31 -07:00
|
|
|
|
2018-06-25 22:37:08 -06:00
|
|
|
if (filename.isEmpty())
|
2018-01-03 17:41:31 -07:00
|
|
|
return;
|
|
|
|
|
2018-02-02 04:28:57 -07:00
|
|
|
QString path_abs = QFileInfo(filename).absoluteFilePath();
|
2018-01-03 17:41:31 -07:00
|
|
|
|
|
|
|
// Memcard validity checks
|
|
|
|
if (memcard)
|
|
|
|
{
|
2018-06-25 22:37:08 -06:00
|
|
|
if (File::Exists(filename.toStdString()))
|
2018-01-03 17:41:31 -07:00
|
|
|
{
|
2020-06-14 18:09:37 -06:00
|
|
|
auto [error_code, mc] = Memcard::GCMemcard::Open(filename.toStdString());
|
2018-06-25 22:37:08 -06:00
|
|
|
|
2019-04-21 07:18:01 -06:00
|
|
|
if (error_code.HasCriticalErrors() || !mc || !mc->IsValid())
|
2018-06-25 22:37:08 -06:00
|
|
|
{
|
2019-08-14 20:08:20 -06:00
|
|
|
ModalMessageBox::critical(
|
|
|
|
this, tr("Error"),
|
|
|
|
tr("The file\n%1\nis either corrupted or not a GameCube memory card file.\n%2")
|
|
|
|
.arg(filename)
|
|
|
|
.arg(GCMemcardManager::GetErrorMessagesForErrorCode(error_code)));
|
2018-06-25 22:37:08 -06:00
|
|
|
return;
|
|
|
|
}
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
|
2018-02-02 04:28:57 -07:00
|
|
|
bool other_slot_memcard =
|
2019-01-24 13:08:21 -07:00
|
|
|
m_slot_combos[slot == SLOT_A_INDEX ? SLOT_B_INDEX : SLOT_A_INDEX]->currentData().toInt() ==
|
2020-08-17 01:07:38 -06:00
|
|
|
static_cast<int>(ExpansionInterface::EXIDeviceType::MemoryCard);
|
2018-02-02 04:28:57 -07:00
|
|
|
if (other_slot_memcard)
|
2018-01-03 17:41:31 -07:00
|
|
|
{
|
2018-02-02 04:28:57 -07:00
|
|
|
QString path_b =
|
2018-07-04 15:01:50 -06:00
|
|
|
QFileInfo(QString::fromStdString(slot == 0 ? Config::Get(Config::MAIN_MEMCARD_B_PATH) :
|
|
|
|
Config::Get(Config::MAIN_MEMCARD_A_PATH)))
|
2018-02-02 04:28:57 -07:00
|
|
|
.absoluteFilePath();
|
|
|
|
|
|
|
|
if (path_abs == path_b)
|
|
|
|
{
|
2019-03-04 12:49:00 -07:00
|
|
|
ModalMessageBox::critical(this, tr("Error"),
|
|
|
|
tr("The same file can't be used in both slots."));
|
2018-02-02 04:28:57 -07:00
|
|
|
return;
|
|
|
|
}
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-17 01:18:22 -06:00
|
|
|
QString path_old;
|
|
|
|
if (memcard)
|
|
|
|
{
|
|
|
|
path_old =
|
2018-07-04 15:01:50 -06:00
|
|
|
QFileInfo(QString::fromStdString(slot == 0 ? Config::Get(Config::MAIN_MEMCARD_A_PATH) :
|
|
|
|
Config::Get(Config::MAIN_MEMCARD_B_PATH)))
|
2018-06-17 01:18:22 -06:00
|
|
|
.absoluteFilePath();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-02 23:07:32 -07:00
|
|
|
path_old =
|
|
|
|
QFileInfo(QString::fromStdString(slot == 0 ? Config::Get(Config::MAIN_AGP_CART_A_PATH) :
|
|
|
|
Config::Get(Config::MAIN_AGP_CART_B_PATH)))
|
|
|
|
.absoluteFilePath();
|
2018-06-17 01:18:22 -06:00
|
|
|
}
|
|
|
|
|
2018-01-03 17:41:31 -07:00
|
|
|
if (memcard)
|
|
|
|
{
|
|
|
|
if (slot == SLOT_A_INDEX)
|
|
|
|
{
|
2018-07-04 15:01:50 -06:00
|
|
|
Config::SetBase(Config::MAIN_MEMCARD_A_PATH, path_abs.toStdString());
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-07-04 15:01:50 -06:00
|
|
|
Config::SetBase(Config::MAIN_MEMCARD_B_PATH, path_abs.toStdString());
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (slot == SLOT_A_INDEX)
|
|
|
|
{
|
2022-01-02 23:07:32 -07:00
|
|
|
Config::SetBase(Config::MAIN_AGP_CART_A_PATH, path_abs.toStdString());
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-02 23:07:32 -07:00
|
|
|
Config::SetBase(Config::MAIN_AGP_CART_B_PATH, path_abs.toStdString());
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
}
|
2018-06-17 01:18:22 -06:00
|
|
|
|
|
|
|
if (Core::IsRunning() && path_abs != path_old)
|
|
|
|
{
|
|
|
|
ExpansionInterface::ChangeDevice(
|
|
|
|
// SlotB is on channel 1, slotA and SP1 are on 0
|
|
|
|
slot,
|
|
|
|
// The device enum to change to
|
2020-08-17 01:07:38 -06:00
|
|
|
memcard ? ExpansionInterface::EXIDeviceType::MemoryCard :
|
|
|
|
ExpansionInterface::EXIDeviceType::AGP,
|
2018-06-17 01:18:22 -06:00
|
|
|
// SP1 is device 2, slots are device 0
|
|
|
|
0);
|
|
|
|
}
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
|
2021-07-04 04:53:53 -06:00
|
|
|
void GameCubePane::BrowseGBABios()
|
|
|
|
{
|
2021-10-09 20:28:59 -06:00
|
|
|
QString file = QDir::toNativeSeparators(DolphinFileDialog::getOpenFileName(
|
2021-07-04 04:53:53 -06:00
|
|
|
this, tr("Select GBA BIOS"), QString::fromStdString(File::GetUserPath(F_GBABIOS_IDX)),
|
|
|
|
tr("All Files (*)")));
|
|
|
|
if (!file.isEmpty())
|
|
|
|
{
|
|
|
|
m_gba_bios_edit->setText(file);
|
|
|
|
SaveSettings();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameCubePane::BrowseGBARom(size_t index)
|
|
|
|
{
|
|
|
|
QString file = QString::fromStdString(GetOpenGBARom({}));
|
|
|
|
if (!file.isEmpty())
|
|
|
|
{
|
|
|
|
m_gba_rom_edits[index]->setText(file);
|
|
|
|
SaveSettings();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameCubePane::SaveRomPathChanged()
|
|
|
|
{
|
|
|
|
m_gba_saves_edit->setEnabled(!m_gba_save_rom_path->isChecked());
|
|
|
|
m_gba_browse_saves->setEnabled(!m_gba_save_rom_path->isChecked());
|
|
|
|
SaveSettings();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameCubePane::BrowseGBASaves()
|
|
|
|
{
|
2021-10-09 20:28:59 -06:00
|
|
|
QString dir = QDir::toNativeSeparators(DolphinFileDialog::getExistingDirectory(
|
|
|
|
this, tr("Select GBA Saves Path"),
|
|
|
|
QString::fromStdString(File::GetUserPath(D_GBASAVES_IDX))));
|
2021-07-04 04:53:53 -06:00
|
|
|
if (!dir.isEmpty())
|
|
|
|
{
|
|
|
|
m_gba_saves_edit->setText(dir);
|
|
|
|
SaveSettings();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-03 17:41:31 -07:00
|
|
|
void GameCubePane::LoadSettings()
|
|
|
|
{
|
|
|
|
// IPL Settings
|
2022-01-02 23:07:32 -07:00
|
|
|
m_skip_main_menu->setChecked(Config::Get(Config::MAIN_SKIP_IPL));
|
|
|
|
m_language_combo->setCurrentIndex(
|
|
|
|
m_language_combo->findData(Config::Get(Config::MAIN_GC_LANGUAGE)));
|
2018-01-03 17:41:31 -07:00
|
|
|
|
|
|
|
bool have_menu = false;
|
|
|
|
|
2021-05-17 13:00:13 -06:00
|
|
|
for (const std::string dir : {USA_DIR, JAP_DIR, EUR_DIR})
|
2018-01-03 17:41:31 -07:00
|
|
|
{
|
2018-03-23 05:35:34 -06:00
|
|
|
const auto path = DIR_SEP + dir + DIR_SEP GC_IPL;
|
2018-01-03 17:41:31 -07:00
|
|
|
if (File::Exists(File::GetUserPath(D_GCUSER_IDX) + path) ||
|
2018-03-23 05:35:34 -06:00
|
|
|
File::Exists(File::GetSysDirectory() + GC_SYS_DIR + path))
|
2018-01-03 17:41:31 -07:00
|
|
|
{
|
|
|
|
have_menu = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_skip_main_menu->setEnabled(have_menu);
|
2021-09-08 14:08:43 -06:00
|
|
|
m_skip_main_menu->setToolTip(have_menu ? QString{} : tr("Put IPL ROMs in User/GC/<region>."));
|
2018-01-03 17:41:31 -07:00
|
|
|
|
|
|
|
// Device Settings
|
|
|
|
for (int i = 0; i < SLOT_COUNT; i++)
|
|
|
|
{
|
2019-01-24 13:08:21 -07:00
|
|
|
QSignalBlocker blocker(m_slot_combos[i]);
|
2020-08-17 01:07:38 -06:00
|
|
|
const ExpansionInterface::EXIDeviceType exi_device =
|
|
|
|
Config::Get(Config::GetInfoForEXIDevice(i));
|
|
|
|
m_slot_combos[i]->setCurrentIndex(m_slot_combos[i]->findData(static_cast<int>(exi_device)));
|
2019-01-24 13:08:21 -07:00
|
|
|
UpdateButton(i);
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
2021-07-04 04:53:53 -06:00
|
|
|
|
|
|
|
#ifdef HAS_LIBMGBA
|
|
|
|
// GBA Settings
|
|
|
|
m_gba_threads->setChecked(Config::Get(Config::MAIN_GBA_THREADS));
|
|
|
|
m_gba_bios_edit->setText(QString::fromStdString(File::GetUserPath(F_GBABIOS_IDX)));
|
|
|
|
m_gba_save_rom_path->setChecked(Config::Get(Config::MAIN_GBA_SAVES_IN_ROM_PATH));
|
|
|
|
m_gba_saves_edit->setText(QString::fromStdString(File::GetUserPath(D_GBASAVES_IDX)));
|
|
|
|
for (size_t i = 0; i < m_gba_rom_edits.size(); ++i)
|
|
|
|
m_gba_rom_edits[i]->setText(QString::fromStdString(Config::Get(Config::MAIN_GBA_ROM_PATHS[i])));
|
|
|
|
#endif
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void GameCubePane::SaveSettings()
|
|
|
|
{
|
2019-03-03 09:58:37 -07:00
|
|
|
Config::ConfigChangeCallbackGuard config_guard;
|
|
|
|
|
2018-01-03 17:41:31 -07:00
|
|
|
// IPL Settings
|
2018-07-19 16:10:37 -06:00
|
|
|
Config::SetBaseOrCurrent(Config::MAIN_SKIP_IPL, m_skip_main_menu->isChecked());
|
2019-01-24 13:08:21 -07:00
|
|
|
Config::SetBaseOrCurrent(Config::MAIN_GC_LANGUAGE, m_language_combo->currentData().toInt());
|
2018-01-03 17:41:31 -07:00
|
|
|
|
2021-07-04 04:53:53 -06:00
|
|
|
// Device Settings
|
2018-01-03 17:41:31 -07:00
|
|
|
for (int i = 0; i < SLOT_COUNT; i++)
|
|
|
|
{
|
2020-08-17 01:07:38 -06:00
|
|
|
const auto dev =
|
|
|
|
static_cast<ExpansionInterface::EXIDeviceType>(m_slot_combos[i]->currentData().toInt());
|
|
|
|
const ExpansionInterface::EXIDeviceType current_exi_device =
|
2022-01-05 23:17:29 -07:00
|
|
|
Config::Get(Config::GetInfoForEXIDevice(i));
|
2018-01-03 17:41:31 -07:00
|
|
|
|
2022-01-05 23:17:29 -07:00
|
|
|
if (Core::IsRunning() && current_exi_device != dev)
|
2018-01-03 17:41:31 -07:00
|
|
|
{
|
|
|
|
ExpansionInterface::ChangeDevice(
|
2018-06-17 01:18:22 -06:00
|
|
|
// SlotB is on channel 1, slotA and SP1 are on 0
|
|
|
|
(i == 1) ? 1 : 0,
|
|
|
|
// The device enum to change to
|
|
|
|
dev,
|
|
|
|
// SP1 is device 2, slots are device 0
|
|
|
|
(i == 2) ? 2 : 0);
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
|
|
|
|
2022-01-05 23:17:29 -07:00
|
|
|
Config::SetBaseOrCurrent(Config::GetInfoForEXIDevice(i), dev);
|
2018-01-03 17:41:31 -07:00
|
|
|
}
|
2021-07-04 04:53:53 -06:00
|
|
|
|
|
|
|
#ifdef HAS_LIBMGBA
|
|
|
|
// GBA Settings
|
|
|
|
if (!NetPlay::IsNetPlayRunning())
|
|
|
|
{
|
|
|
|
Config::SetBaseOrCurrent(Config::MAIN_GBA_THREADS, m_gba_threads->isChecked());
|
|
|
|
Config::SetBaseOrCurrent(Config::MAIN_GBA_BIOS_PATH, m_gba_bios_edit->text().toStdString());
|
|
|
|
Config::SetBaseOrCurrent(Config::MAIN_GBA_SAVES_IN_ROM_PATH, m_gba_save_rom_path->isChecked());
|
|
|
|
Config::SetBaseOrCurrent(Config::MAIN_GBA_SAVES_PATH, m_gba_saves_edit->text().toStdString());
|
|
|
|
File::SetUserPath(F_GBABIOS_IDX, Config::Get(Config::MAIN_GBA_BIOS_PATH));
|
|
|
|
File::SetUserPath(D_GBASAVES_IDX, Config::Get(Config::MAIN_GBA_SAVES_PATH));
|
|
|
|
for (size_t i = 0; i < m_gba_rom_edits.size(); ++i)
|
|
|
|
{
|
|
|
|
Config::SetBaseOrCurrent(Config::MAIN_GBA_ROM_PATHS[i],
|
|
|
|
m_gba_rom_edits[i]->text().toStdString());
|
|
|
|
}
|
2021-07-04 05:33:58 -06:00
|
|
|
|
|
|
|
auto server = Settings::Instance().GetNetPlayServer();
|
|
|
|
if (server)
|
|
|
|
server->SetGBAConfig(server->GetGBAConfig(), true);
|
2021-07-04 04:53:53 -06:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-01-03 17:41:31 -07:00
|
|
|
LoadSettings();
|
|
|
|
}
|
2021-07-04 04:53:53 -06:00
|
|
|
|
|
|
|
std::string GameCubePane::GetOpenGBARom(std::string_view title)
|
|
|
|
{
|
|
|
|
QString caption = tr("Select GBA ROM");
|
|
|
|
if (!title.empty())
|
|
|
|
caption += QStringLiteral(": %1").arg(QString::fromStdString(std::string(title)));
|
|
|
|
return QDir::toNativeSeparators(
|
2021-10-09 20:28:59 -06:00
|
|
|
DolphinFileDialog::getOpenFileName(
|
2021-07-04 04:53:53 -06:00
|
|
|
nullptr, caption, QString(),
|
|
|
|
tr("Game Boy Advance ROMs (*.gba *.gbc *.gb *.7z *.zip *.agb *.mb *.rom *.bin);;"
|
|
|
|
"All Files (*)")))
|
|
|
|
.toStdString();
|
|
|
|
}
|