mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Merge pull request #7629 from JosJuice/auto-disc-change
Automatic disc change for 2-disc games
This commit is contained in:
@ -737,6 +737,17 @@ bool GameList::HasMultipleSelected() const
|
||||
m_grid->selectionModel()->selectedIndexes().size() > 1;
|
||||
}
|
||||
|
||||
std::shared_ptr<const UICommon::GameFile> GameList::FindGame(const std::string& path) const
|
||||
{
|
||||
return m_model->FindGame(path);
|
||||
}
|
||||
|
||||
std::shared_ptr<const UICommon::GameFile>
|
||||
GameList::FindSecondDisc(const UICommon::GameFile& game) const
|
||||
{
|
||||
return m_model->FindSecondDisc(game);
|
||||
}
|
||||
|
||||
void GameList::SetViewColumn(int col, bool view)
|
||||
{
|
||||
m_list->setColumnHidden(col, !view);
|
||||
|
@ -30,6 +30,8 @@ public:
|
||||
std::shared_ptr<const UICommon::GameFile> GetSelectedGame() const;
|
||||
QList<std::shared_ptr<const UICommon::GameFile>> GetSelectedGames() const;
|
||||
bool HasMultipleSelected() const;
|
||||
std::shared_ptr<const UICommon::GameFile> FindGame(const std::string& path) const;
|
||||
std::shared_ptr<const UICommon::GameFile> FindSecondDisc(const UICommon::GameFile& game) const;
|
||||
|
||||
void SetListView() { SetPreferredView(true); }
|
||||
void SetGridView() { SetPreferredView(false); }
|
||||
|
@ -278,7 +278,7 @@ void GameListModel::AddGame(const std::shared_ptr<const UICommon::GameFile>& gam
|
||||
|
||||
void GameListModel::UpdateGame(const std::shared_ptr<const UICommon::GameFile>& game)
|
||||
{
|
||||
int index = FindGame(game->GetFilePath());
|
||||
int index = FindGameIndex(game->GetFilePath());
|
||||
if (index < 0)
|
||||
{
|
||||
AddGame(game);
|
||||
@ -292,7 +292,7 @@ void GameListModel::UpdateGame(const std::shared_ptr<const UICommon::GameFile>&
|
||||
|
||||
void GameListModel::RemoveGame(const std::string& path)
|
||||
{
|
||||
int entry = FindGame(path);
|
||||
int entry = FindGameIndex(path);
|
||||
if (entry < 0)
|
||||
return;
|
||||
|
||||
@ -301,7 +301,13 @@ void GameListModel::RemoveGame(const std::string& path)
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
int GameListModel::FindGame(const std::string& path) const
|
||||
std::shared_ptr<const UICommon::GameFile> GameListModel::FindGame(const std::string& path) const
|
||||
{
|
||||
const int index = FindGameIndex(path);
|
||||
return index < 0 ? nullptr : m_games[index];
|
||||
}
|
||||
|
||||
int GameListModel::FindGameIndex(const std::string& path) const
|
||||
{
|
||||
for (int i = 0; i < m_games.size(); i++)
|
||||
{
|
||||
@ -311,6 +317,29 @@ int GameListModel::FindGame(const std::string& path) const
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::shared_ptr<const UICommon::GameFile>
|
||||
GameListModel::FindSecondDisc(const UICommon::GameFile& game) const
|
||||
{
|
||||
std::shared_ptr<const UICommon::GameFile> match_without_revision = nullptr;
|
||||
|
||||
if (DiscIO::IsDisc(game.GetPlatform()))
|
||||
{
|
||||
for (auto& other_game : m_games)
|
||||
{
|
||||
if (game.GetGameID() == other_game->GetGameID() &&
|
||||
game.GetDiscNumber() != other_game->GetDiscNumber())
|
||||
{
|
||||
if (game.GetRevision() == other_game->GetRevision())
|
||||
return other_game;
|
||||
else
|
||||
match_without_revision = other_game;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return match_without_revision;
|
||||
}
|
||||
|
||||
void GameListModel::SetSearchTerm(const QString& term)
|
||||
{
|
||||
m_term = term;
|
||||
|
@ -63,6 +63,9 @@ public:
|
||||
void UpdateGame(const std::shared_ptr<const UICommon::GameFile>& game);
|
||||
void RemoveGame(const std::string& path);
|
||||
|
||||
std::shared_ptr<const UICommon::GameFile> FindGame(const std::string& path) const;
|
||||
std::shared_ptr<const UICommon::GameFile> FindSecondDisc(const UICommon::GameFile& game) const;
|
||||
|
||||
void SetScale(float scale);
|
||||
float GetScale() const;
|
||||
|
||||
@ -79,7 +82,7 @@ public:
|
||||
|
||||
private:
|
||||
// Index in m_games, or -1 if it isn't found
|
||||
int FindGame(const std::string& path) const;
|
||||
int FindGameIndex(const std::string& path) const;
|
||||
|
||||
QStringList m_tag_list;
|
||||
QMap<QString, QVariant> m_game_tags;
|
||||
|
@ -13,6 +13,7 @@
|
||||
<string>gcm</string>
|
||||
<string>gcz</string>
|
||||
<string>iso</string>
|
||||
<string>m3u</string>
|
||||
<string>tgc</string>
|
||||
<string>wad</string>
|
||||
<string>wbfs</string>
|
||||
|
@ -147,7 +147,10 @@ int main(int argc, char* argv[])
|
||||
std::unique_ptr<BootParameters> boot;
|
||||
if (options.is_set("exec"))
|
||||
{
|
||||
boot = BootParameters::GenerateFromFile(static_cast<const char*>(options.get("exec")));
|
||||
const std::list<std::string> paths_list = options.all("exec");
|
||||
const std::vector<std::string> paths{std::make_move_iterator(std::begin(paths_list)),
|
||||
std::make_move_iterator(std::end(paths_list))};
|
||||
boot = BootParameters::GenerateFromFile(paths);
|
||||
}
|
||||
else if (options.is_set("nand_title"))
|
||||
{
|
||||
|
@ -168,6 +168,17 @@ static WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
||||
return wsi;
|
||||
}
|
||||
|
||||
static std::vector<std::string> StringListToStdVector(QStringList list)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
result.reserve(list.size());
|
||||
|
||||
for (const QString& s : list)
|
||||
result.push_back(s.toStdString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<BootParameters> boot_parameters) : QMainWindow(nullptr)
|
||||
{
|
||||
setWindowTitle(QString::fromStdString(Common::scm_rev_str));
|
||||
@ -387,7 +398,7 @@ void MainWindow::ConnectMenuBar()
|
||||
connect(m_menu_bar, &MenuBar::EjectDisc, this, &MainWindow::EjectDisc);
|
||||
connect(m_menu_bar, &MenuBar::ChangeDisc, this, &MainWindow::ChangeDisc);
|
||||
connect(m_menu_bar, &MenuBar::BootDVDBackup, this,
|
||||
[this](const QString& drive) { StartGame(drive); });
|
||||
[this](const QString& drive) { StartGame(drive, ScanForSecondDisc::No); });
|
||||
|
||||
// Emulation
|
||||
connect(m_menu_bar, &MenuBar::Pause, this, &MainWindow::Pause);
|
||||
@ -610,30 +621,30 @@ void MainWindow::RefreshGameList()
|
||||
Settings::Instance().RefreshGameList();
|
||||
}
|
||||
|
||||
QString MainWindow::PromptFileName()
|
||||
QStringList MainWindow::PromptFileNames()
|
||||
{
|
||||
auto& settings = Settings::Instance().GetQSettings();
|
||||
QString path = QFileDialog::getOpenFileName(
|
||||
QStringList paths = QFileDialog::getOpenFileNames(
|
||||
this, tr("Select a File"),
|
||||
settings.value(QStringLiteral("mainwindow/lastdir"), QStringLiteral("")).toString(),
|
||||
tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad *.dff);;"
|
||||
tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad *.dff *.m3u);;"
|
||||
"All Files (*)"));
|
||||
|
||||
if (!path.isEmpty())
|
||||
if (!paths.isEmpty())
|
||||
{
|
||||
settings.setValue(QStringLiteral("mainwindow/lastdir"),
|
||||
QFileInfo(path).absoluteDir().absolutePath());
|
||||
QFileInfo(paths.front()).absoluteDir().absolutePath());
|
||||
}
|
||||
|
||||
return path;
|
||||
return paths;
|
||||
}
|
||||
|
||||
void MainWindow::ChangeDisc()
|
||||
{
|
||||
QString file = PromptFileName();
|
||||
std::vector<std::string> paths = StringListToStdVector(PromptFileNames());
|
||||
|
||||
if (!file.isEmpty())
|
||||
Core::RunAsCPUThread([&file] { DVDInterface::ChangeDisc(file.toStdString()); });
|
||||
if (!paths.empty())
|
||||
Core::RunAsCPUThread([&paths] { DVDInterface::ChangeDisc(paths); });
|
||||
}
|
||||
|
||||
void MainWindow::EjectDisc()
|
||||
@ -643,9 +654,9 @@ void MainWindow::EjectDisc()
|
||||
|
||||
void MainWindow::Open()
|
||||
{
|
||||
QString file = PromptFileName();
|
||||
if (!file.isEmpty())
|
||||
StartGame(file);
|
||||
QStringList files = PromptFileNames();
|
||||
if (!files.isEmpty())
|
||||
StartGame(StringListToStdVector(files));
|
||||
}
|
||||
|
||||
void MainWindow::Play(const std::optional<std::string>& savestate_path)
|
||||
@ -664,7 +675,7 @@ void MainWindow::Play(const std::optional<std::string>& savestate_path)
|
||||
std::shared_ptr<const UICommon::GameFile> selection = m_game_list->GetSelectedGame();
|
||||
if (selection)
|
||||
{
|
||||
StartGame(selection->GetFilePath(), savestate_path);
|
||||
StartGame(selection->GetFilePath(), ScanForSecondDisc::Yes, savestate_path);
|
||||
EnableScreenSaver(false);
|
||||
}
|
||||
else
|
||||
@ -672,7 +683,7 @@ void MainWindow::Play(const std::optional<std::string>& savestate_path)
|
||||
const QString default_path = QString::fromStdString(Config::Get(Config::MAIN_DEFAULT_ISO));
|
||||
if (!default_path.isEmpty() && QFile::exists(default_path))
|
||||
{
|
||||
StartGame(default_path, savestate_path);
|
||||
StartGame(default_path, ScanForSecondDisc::Yes, savestate_path);
|
||||
EnableScreenSaver(false);
|
||||
}
|
||||
else
|
||||
@ -833,17 +844,46 @@ void MainWindow::ScreenShot()
|
||||
Core::SaveScreenShot();
|
||||
}
|
||||
|
||||
void MainWindow::StartGame(const QString& path, const std::optional<std::string>& savestate_path)
|
||||
void MainWindow::ScanForSecondDiscAndStartGame(const UICommon::GameFile& game,
|
||||
const std::optional<std::string>& savestate_path)
|
||||
{
|
||||
StartGame(path.toStdString(), savestate_path);
|
||||
auto second_game = m_game_list->FindSecondDisc(game);
|
||||
|
||||
std::vector<std::string> paths = {game.GetFilePath()};
|
||||
if (second_game != nullptr)
|
||||
paths.push_back(second_game->GetFilePath());
|
||||
|
||||
StartGame(paths, savestate_path);
|
||||
}
|
||||
|
||||
void MainWindow::StartGame(const std::string& path,
|
||||
void MainWindow::StartGame(const QString& path, ScanForSecondDisc scan,
|
||||
const std::optional<std::string>& savestate_path)
|
||||
{
|
||||
StartGame(path.toStdString(), scan, savestate_path);
|
||||
}
|
||||
|
||||
void MainWindow::StartGame(const std::string& path, ScanForSecondDisc scan,
|
||||
const std::optional<std::string>& savestate_path)
|
||||
{
|
||||
if (scan == ScanForSecondDisc::Yes)
|
||||
{
|
||||
std::shared_ptr<const UICommon::GameFile> game = m_game_list->FindGame(path);
|
||||
if (game != nullptr)
|
||||
{
|
||||
ScanForSecondDiscAndStartGame(*game, savestate_path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
StartGame(BootParameters::GenerateFromFile(path, savestate_path));
|
||||
}
|
||||
|
||||
void MainWindow::StartGame(const std::vector<std::string>& paths,
|
||||
const std::optional<std::string>& savestate_path)
|
||||
{
|
||||
StartGame(BootParameters::GenerateFromFile(paths, savestate_path));
|
||||
}
|
||||
|
||||
void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
|
||||
{
|
||||
// If we're running, only start a new game once we've stopped the last.
|
||||
@ -1075,7 +1115,7 @@ void MainWindow::ShowFIFOPlayer()
|
||||
{
|
||||
m_fifo_window = new FIFOPlayerWindow(this);
|
||||
connect(m_fifo_window, &FIFOPlayerWindow::LoadFIFORequested, this,
|
||||
[this](const QString& path) { StartGame(path); });
|
||||
[this](const QString& path) { StartGame(path, ScanForSecondDisc::No); });
|
||||
}
|
||||
|
||||
m_fifo_window->show();
|
||||
@ -1170,7 +1210,7 @@ void MainWindow::NetPlayInit()
|
||||
#endif
|
||||
|
||||
connect(m_netplay_dialog, &NetPlayDialog::Boot, this,
|
||||
[this](const QString& path) { StartGame(path); });
|
||||
[this](const QString& path) { StartGame(path, ScanForSecondDisc::Yes); });
|
||||
connect(m_netplay_dialog, &NetPlayDialog::Stop, this, &MainWindow::ForceStop);
|
||||
connect(m_netplay_dialog, &NetPlayDialog::rejected, this, &MainWindow::NetPlayQuit);
|
||||
connect(m_netplay_setup_dialog, &NetPlaySetupDialog::Join, this, &MainWindow::NetPlayJoin);
|
||||
@ -1346,38 +1386,48 @@ void MainWindow::dragEnterEvent(QDragEnterEvent* event)
|
||||
|
||||
void MainWindow::dropEvent(QDropEvent* event)
|
||||
{
|
||||
const auto& urls = event->mimeData()->urls();
|
||||
const QList<QUrl>& urls = event->mimeData()->urls();
|
||||
if (urls.empty())
|
||||
return;
|
||||
|
||||
const auto& url = urls[0];
|
||||
QFileInfo file_info(url.toLocalFile());
|
||||
QStringList files;
|
||||
QStringList folders;
|
||||
|
||||
auto path = file_info.filePath();
|
||||
|
||||
if (!file_info.exists() || !file_info.isReadable())
|
||||
for (const QUrl& url : urls)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to open '%1'").arg(path));
|
||||
return;
|
||||
QFileInfo file_info(url.toLocalFile());
|
||||
QString path = file_info.filePath();
|
||||
|
||||
if (!file_info.exists() || !file_info.isReadable())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to open '%1'").arg(path));
|
||||
return;
|
||||
}
|
||||
|
||||
(file_info.isFile() ? files : folders).append(path);
|
||||
}
|
||||
|
||||
if (file_info.isFile())
|
||||
if (!files.isEmpty())
|
||||
{
|
||||
StartGame(path);
|
||||
StartGame(StringListToStdVector(files));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& settings = Settings::Instance();
|
||||
Settings& settings = Settings::Instance();
|
||||
const bool show_confirm = settings.GetPaths().size() != 0;
|
||||
|
||||
if (settings.GetPaths().size() != 0)
|
||||
for (const QString& folder : folders)
|
||||
{
|
||||
if (QMessageBox::question(
|
||||
this, tr("Confirm"),
|
||||
tr("Do you want to add \"%1\" to the list of Game Paths?").arg(path)) !=
|
||||
QMessageBox::Yes)
|
||||
return;
|
||||
if (show_confirm)
|
||||
{
|
||||
if (QMessageBox::question(
|
||||
this, tr("Confirm"),
|
||||
tr("Do you want to add \"%1\" to the list of Game Paths?").arg(folder)) !=
|
||||
QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
settings.AddPath(folder);
|
||||
}
|
||||
settings.AddPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QStringList>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
@ -47,6 +48,11 @@ namespace DiscIO
|
||||
enum class Region;
|
||||
}
|
||||
|
||||
namespace UICommon
|
||||
{
|
||||
class GameFile;
|
||||
}
|
||||
|
||||
namespace X11Utils
|
||||
{
|
||||
class XRRConfiguration;
|
||||
@ -115,8 +121,20 @@ private:
|
||||
|
||||
void InitCoreCallbacks();
|
||||
|
||||
void StartGame(const QString& path, const std::optional<std::string>& savestate_path = {});
|
||||
void StartGame(const std::string& path, const std::optional<std::string>& savestate_path = {});
|
||||
enum class ScanForSecondDisc
|
||||
{
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
|
||||
void ScanForSecondDiscAndStartGame(const UICommon::GameFile& game,
|
||||
const std::optional<std::string>& savestate_path = {});
|
||||
void StartGame(const QString& path, ScanForSecondDisc scan,
|
||||
const std::optional<std::string>& savestate_path = {});
|
||||
void StartGame(const std::string& path, ScanForSecondDisc scan,
|
||||
const std::optional<std::string>& savestate_path = {});
|
||||
void StartGame(const std::vector<std::string>& paths,
|
||||
const std::optional<std::string>& savestate_path = {});
|
||||
void StartGame(std::unique_ptr<BootParameters>&& parameters);
|
||||
void ShowRenderWidget();
|
||||
void HideRenderWidget(bool reinit = true);
|
||||
@ -155,7 +173,7 @@ private:
|
||||
void ChangeDisc();
|
||||
void EjectDisc();
|
||||
|
||||
QString PromptFileName();
|
||||
QStringList PromptFileNames();
|
||||
|
||||
void EnableScreenSaver(bool enable);
|
||||
|
||||
|
@ -96,6 +96,7 @@ void GeneralPane::ConnectLayout()
|
||||
{
|
||||
connect(m_checkbox_dualcore, &QCheckBox::toggled, this, &GeneralPane::OnSaveConfig);
|
||||
connect(m_checkbox_cheats, &QCheckBox::toggled, this, &GeneralPane::OnSaveConfig);
|
||||
connect(m_checkbox_auto_disc_change, &QCheckBox::toggled, this, &GeneralPane::OnSaveConfig);
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
connect(m_checkbox_discord_presence, &QCheckBox::toggled, this, &GeneralPane::OnSaveConfig);
|
||||
#endif
|
||||
@ -137,6 +138,9 @@ void GeneralPane::CreateBasic()
|
||||
m_checkbox_cheats = new QCheckBox(tr("Enable Cheats"));
|
||||
basic_group_layout->addWidget(m_checkbox_cheats);
|
||||
|
||||
m_checkbox_auto_disc_change = new QCheckBox(tr("Change Discs Automatically"));
|
||||
basic_group_layout->addWidget(m_checkbox_auto_disc_change);
|
||||
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
m_checkbox_discord_presence = new QCheckBox(tr("Show Current Game on Discord"));
|
||||
basic_group_layout->addWidget(m_checkbox_discord_presence);
|
||||
@ -236,6 +240,7 @@ void GeneralPane::LoadConfig()
|
||||
#endif
|
||||
m_checkbox_dualcore->setChecked(SConfig::GetInstance().bCPUThread);
|
||||
m_checkbox_cheats->setChecked(Settings::Instance().GetCheatsEnabled());
|
||||
m_checkbox_auto_disc_change->setChecked(Config::Get(Config::MAIN_AUTO_DISC_CHANGE));
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
m_checkbox_discord_presence->setChecked(Config::Get(Config::MAIN_USE_DISCORD_PRESENCE));
|
||||
#endif
|
||||
@ -295,6 +300,7 @@ void GeneralPane::OnSaveConfig()
|
||||
settings.bCPUThread = m_checkbox_dualcore->isChecked();
|
||||
Config::SetBaseOrCurrent(Config::MAIN_CPU_THREAD, m_checkbox_dualcore->isChecked());
|
||||
Settings::Instance().SetCheatsEnabled(m_checkbox_cheats->isChecked());
|
||||
Config::SetBase(Config::MAIN_AUTO_DISC_CHANGE, m_checkbox_auto_disc_change->isChecked());
|
||||
Config::SetBaseOrCurrent(Config::MAIN_ENABLE_CHEATS, m_checkbox_cheats->isChecked());
|
||||
settings.m_EmulationSpeed = m_combobox_speedlimit->currentIndex() * 0.1f;
|
||||
|
||||
|
@ -44,6 +44,7 @@ private:
|
||||
QComboBox* m_combobox_update_track;
|
||||
QCheckBox* m_checkbox_dualcore;
|
||||
QCheckBox* m_checkbox_cheats;
|
||||
QCheckBox* m_checkbox_auto_disc_change;
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
QCheckBox* m_checkbox_discord_presence;
|
||||
#endif
|
||||
|
@ -43,7 +43,7 @@ void PathPane::BrowseDefaultGame()
|
||||
{
|
||||
QString file = QDir::toNativeSeparators(QFileDialog::getOpenFileName(
|
||||
this, tr("Select a Game"), Settings::Instance().GetDefaultGame(),
|
||||
tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad);;"
|
||||
tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad *.m3u);;"
|
||||
"All Files (*)")));
|
||||
|
||||
if (!file.isEmpty())
|
||||
|
Reference in New Issue
Block a user