mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-14 08:12:16 +00:00
1214 lines
46 KiB
C++
1214 lines
46 KiB
C++
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "SDL3/SDL_events.h"
|
|
|
|
#include <QDockWidget>
|
|
#include <QKeyEvent>
|
|
#include <QPlainTextEdit>
|
|
#include <QProgressDialog>
|
|
#include <QStatusBar>
|
|
|
|
#include "about_dialog.h"
|
|
#include "cheats_patches.h"
|
|
#ifdef ENABLE_UPDATER
|
|
#include "check_update.h"
|
|
#endif
|
|
#include "common/io_file.h"
|
|
#include "common/path_util.h"
|
|
#include "common/scm_rev.h"
|
|
#include "common/string_util.h"
|
|
#include "common/version.h"
|
|
#include "control_settings.h"
|
|
#include "game_install_dialog.h"
|
|
#include "kbm_gui.h"
|
|
#include "main_window.h"
|
|
#include "settings_dialog.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_instance.h"
|
|
#ifdef ENABLE_DISCORD_RPC
|
|
#include "common/discord_rpc_handler.h"
|
|
#endif
|
|
|
|
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
|
|
ui->setupUi(this);
|
|
installEventFilter(this);
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
}
|
|
|
|
MainWindow::~MainWindow() {
|
|
SaveWindowState();
|
|
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
|
Config::saveMainWindow(config_dir / "config.toml");
|
|
}
|
|
|
|
bool MainWindow::Init() {
|
|
auto start = std::chrono::steady_clock::now();
|
|
// setup ui
|
|
AddUiWidgets();
|
|
CreateActions();
|
|
CreateRecentGameActions();
|
|
ConfigureGuiFromSettings();
|
|
LoadTranslation();
|
|
CreateDockWindows();
|
|
CreateConnects();
|
|
SetLastUsedTheme();
|
|
SetLastIconSizeBullet();
|
|
GetPhysicalDevices();
|
|
// show ui
|
|
setMinimumSize(720, 405);
|
|
std::string window_title = "";
|
|
if (Common::isRelease) {
|
|
window_title = fmt::format("shadPS4 v{}", Common::VERSION);
|
|
} else {
|
|
std::string remote_url(Common::g_scm_remote_url);
|
|
std::string remote_host;
|
|
try {
|
|
remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
|
} catch (...) {
|
|
remote_host = "unknown";
|
|
}
|
|
if (remote_host == "shadps4-emu" || remote_url.length() == 0) {
|
|
window_title = fmt::format("shadPS4 v{} {} {}", Common::VERSION, Common::g_scm_branch,
|
|
Common::g_scm_desc);
|
|
} else {
|
|
window_title = fmt::format("shadPS4 v{} {}/{} {}", Common::VERSION, remote_host,
|
|
Common::g_scm_branch, Common::g_scm_desc);
|
|
}
|
|
}
|
|
setWindowTitle(QString::fromStdString(window_title));
|
|
this->show();
|
|
// load game list
|
|
LoadGameLists();
|
|
#ifdef ENABLE_UPDATER
|
|
// Check for update
|
|
CheckUpdateMain(true);
|
|
#endif
|
|
|
|
auto end = std::chrono::steady_clock::now();
|
|
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
|
statusBar.reset(new QStatusBar);
|
|
this->setStatusBar(statusBar.data());
|
|
// Update status bar
|
|
int numGames = m_game_info->m_games.size();
|
|
QString statusMessage = tr("Games: ") + QString::number(numGames) + " (" +
|
|
QString::number(duration.count()) + "ms)";
|
|
statusBar->showMessage(statusMessage);
|
|
|
|
#ifdef ENABLE_DISCORD_RPC
|
|
if (Config::getEnableDiscordRPC()) {
|
|
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
|
|
rpc->init();
|
|
rpc->setStatusIdling();
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
void MainWindow::CreateActions() {
|
|
// create action group for icon size
|
|
m_icon_size_act_group = new QActionGroup(this);
|
|
m_icon_size_act_group->addAction(ui->setIconSizeTinyAct);
|
|
m_icon_size_act_group->addAction(ui->setIconSizeSmallAct);
|
|
m_icon_size_act_group->addAction(ui->setIconSizeMediumAct);
|
|
m_icon_size_act_group->addAction(ui->setIconSizeLargeAct);
|
|
|
|
// create action group for list mode
|
|
m_list_mode_act_group = new QActionGroup(this);
|
|
m_list_mode_act_group->addAction(ui->setlistModeListAct);
|
|
m_list_mode_act_group->addAction(ui->setlistModeGridAct);
|
|
m_list_mode_act_group->addAction(ui->setlistElfAct);
|
|
|
|
// create action group for themes
|
|
m_theme_act_group = new QActionGroup(this);
|
|
m_theme_act_group->addAction(ui->setThemeDark);
|
|
m_theme_act_group->addAction(ui->setThemeLight);
|
|
m_theme_act_group->addAction(ui->setThemeGreen);
|
|
m_theme_act_group->addAction(ui->setThemeBlue);
|
|
m_theme_act_group->addAction(ui->setThemeViolet);
|
|
m_theme_act_group->addAction(ui->setThemeGruvbox);
|
|
m_theme_act_group->addAction(ui->setThemeTokyoNight);
|
|
m_theme_act_group->addAction(ui->setThemeOled);
|
|
}
|
|
|
|
void MainWindow::PauseGame() {
|
|
SDL_Event event;
|
|
SDL_memset(&event, 0, sizeof(event));
|
|
event.type = SDL_EVENT_TOGGLE_PAUSE;
|
|
is_paused = !is_paused;
|
|
UpdateToolbarButtons();
|
|
SDL_PushEvent(&event);
|
|
}
|
|
|
|
void MainWindow::toggleLabelsUnderIcons() {
|
|
bool showLabels = ui->toggleLabelsAct->isChecked();
|
|
Config::setShowLabelsUnderIcons();
|
|
UpdateToolbarLabels();
|
|
if (isGameRunning) {
|
|
UpdateToolbarButtons();
|
|
}
|
|
}
|
|
|
|
void MainWindow::toggleFullscreen() {
|
|
SDL_Event event;
|
|
SDL_memset(&event, 0, sizeof(event));
|
|
event.type = SDL_EVENT_TOGGLE_FULLSCREEN;
|
|
SDL_PushEvent(&event);
|
|
}
|
|
|
|
QWidget* MainWindow::createButtonWithLabel(QPushButton* button, const QString& labelText,
|
|
bool showLabel) {
|
|
QWidget* container = new QWidget(this);
|
|
QVBoxLayout* layout = new QVBoxLayout(container);
|
|
layout->setAlignment(Qt::AlignCenter | Qt::AlignBottom);
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
layout->addWidget(button);
|
|
|
|
QLabel* label = nullptr;
|
|
if (showLabel && ui->toggleLabelsAct->isChecked()) {
|
|
label = new QLabel(labelText, this);
|
|
label->setAlignment(Qt::AlignCenter | Qt::AlignBottom);
|
|
layout->addWidget(label);
|
|
button->setToolTip("");
|
|
} else {
|
|
button->setToolTip(labelText);
|
|
}
|
|
|
|
container->setLayout(layout);
|
|
container->setProperty("buttonLabel", QVariant::fromValue(label));
|
|
return container;
|
|
}
|
|
|
|
QWidget* createSpacer(QWidget* parent) {
|
|
QWidget* spacer = new QWidget(parent);
|
|
spacer->setFixedWidth(15);
|
|
spacer->setFixedHeight(15);
|
|
return spacer;
|
|
}
|
|
|
|
void MainWindow::AddUiWidgets() {
|
|
// add toolbar widgets
|
|
QApplication::setStyle("Fusion");
|
|
|
|
bool showLabels = ui->toggleLabelsAct->isChecked();
|
|
ui->toolBar->clear();
|
|
|
|
ui->toolBar->addWidget(createSpacer(this));
|
|
ui->toolBar->addWidget(createButtonWithLabel(ui->playButton, tr("Play"), showLabels));
|
|
ui->toolBar->addWidget(createButtonWithLabel(ui->pauseButton, tr("Pause"), showLabels));
|
|
ui->toolBar->addWidget(createButtonWithLabel(ui->stopButton, tr("Stop"), showLabels));
|
|
ui->toolBar->addWidget(createButtonWithLabel(ui->restartButton, tr("Restart"), showLabels));
|
|
ui->toolBar->addWidget(createSpacer(this));
|
|
ui->toolBar->addWidget(createButtonWithLabel(ui->settingsButton, tr("Settings"), showLabels));
|
|
ui->toolBar->addWidget(
|
|
createButtonWithLabel(ui->fullscreenButton, tr("Full Screen"), showLabels));
|
|
ui->toolBar->addWidget(createSpacer(this));
|
|
ui->toolBar->addWidget(
|
|
createButtonWithLabel(ui->controllerButton, tr("Controllers"), showLabels));
|
|
ui->toolBar->addWidget(createButtonWithLabel(ui->keyboardButton, tr("Keyboard"), showLabels));
|
|
ui->toolBar->addWidget(createSpacer(this));
|
|
QFrame* line = new QFrame(this);
|
|
line->setFrameShape(QFrame::VLine);
|
|
line->setFrameShadow(QFrame::Sunken);
|
|
line->setMinimumWidth(2);
|
|
ui->toolBar->addWidget(line);
|
|
ui->toolBar->addWidget(createSpacer(this));
|
|
if (showLabels) {
|
|
QLabel* pauseButtonLabel = ui->pauseButton->parentWidget()->findChild<QLabel*>();
|
|
if (pauseButtonLabel) {
|
|
pauseButtonLabel->setVisible(false);
|
|
}
|
|
}
|
|
ui->toolBar->addWidget(
|
|
createButtonWithLabel(ui->refreshButton, tr("Refresh List"), showLabels));
|
|
ui->toolBar->addWidget(createSpacer(this));
|
|
|
|
QBoxLayout* toolbarLayout = new QBoxLayout(QBoxLayout::TopToBottom);
|
|
toolbarLayout->setSpacing(2);
|
|
toolbarLayout->setContentsMargins(2, 2, 2, 2);
|
|
ui->sizeSliderContainer->setFixedWidth(150);
|
|
|
|
QWidget* searchSliderContainer = new QWidget(this);
|
|
QBoxLayout* searchSliderLayout = new QBoxLayout(QBoxLayout::TopToBottom);
|
|
searchSliderLayout->setContentsMargins(0, 0, 6, 6);
|
|
searchSliderLayout->setSpacing(2);
|
|
ui->mw_searchbar->setFixedWidth(150);
|
|
|
|
searchSliderLayout->addWidget(ui->sizeSliderContainer);
|
|
searchSliderLayout->addWidget(ui->mw_searchbar);
|
|
|
|
searchSliderContainer->setLayout(searchSliderLayout);
|
|
|
|
ui->toolBar->addWidget(searchSliderContainer);
|
|
|
|
if (!showLabels) {
|
|
toolbarLayout->addWidget(searchSliderContainer);
|
|
}
|
|
|
|
ui->playButton->setVisible(true);
|
|
ui->pauseButton->setVisible(false);
|
|
}
|
|
|
|
void MainWindow::UpdateToolbarButtons() {
|
|
// add toolbar widgets when game is running
|
|
bool showLabels = ui->toggleLabelsAct->isChecked();
|
|
|
|
ui->playButton->setVisible(false);
|
|
ui->pauseButton->setVisible(true);
|
|
|
|
if (showLabels) {
|
|
QLabel* playButtonLabel = ui->playButton->parentWidget()->findChild<QLabel*>();
|
|
if (playButtonLabel)
|
|
playButtonLabel->setVisible(false);
|
|
}
|
|
|
|
if (is_paused) {
|
|
ui->pauseButton->setIcon(ui->playButton->icon());
|
|
ui->pauseButton->setToolTip(tr("Resume"));
|
|
} else {
|
|
if (isIconBlack) {
|
|
ui->pauseButton->setIcon(QIcon(":images/pause_icon.png"));
|
|
} else {
|
|
ui->pauseButton->setIcon(RecolorIcon(QIcon(":images/pause_icon.png"), isWhite));
|
|
}
|
|
ui->pauseButton->setToolTip(tr("Pause"));
|
|
}
|
|
|
|
if (showLabels) {
|
|
QLabel* pauseButtonLabel = ui->pauseButton->parentWidget()->findChild<QLabel*>();
|
|
if (pauseButtonLabel) {
|
|
pauseButtonLabel->setText(is_paused ? tr("Resume") : tr("Pause"));
|
|
pauseButtonLabel->setVisible(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::UpdateToolbarLabels() {
|
|
AddUiWidgets();
|
|
}
|
|
|
|
void MainWindow::CreateDockWindows() {
|
|
// place holder widget is needed for good health they say :)
|
|
QWidget* phCentralWidget = new QWidget(this);
|
|
setCentralWidget(phCentralWidget);
|
|
|
|
m_dock_widget.reset(new QDockWidget(tr("Game List"), this));
|
|
m_game_list_frame.reset(new GameListFrame(m_game_info, m_compat_info, this));
|
|
m_game_list_frame->setObjectName("gamelist");
|
|
m_game_grid_frame.reset(new GameGridFrame(m_game_info, m_compat_info, this));
|
|
m_game_grid_frame->setObjectName("gamegridlist");
|
|
m_elf_viewer.reset(new ElfViewer(this));
|
|
m_elf_viewer->setObjectName("elflist");
|
|
|
|
int table_mode = Config::getTableMode();
|
|
int slider_pos = 0;
|
|
if (table_mode == 0) { // List
|
|
m_game_grid_frame->hide();
|
|
m_elf_viewer->hide();
|
|
m_game_list_frame->show();
|
|
m_dock_widget->setWidget(m_game_list_frame.data());
|
|
slider_pos = Config::getSliderPosition();
|
|
ui->sizeSlider->setSliderPosition(slider_pos); // set slider pos at start;
|
|
isTableList = true;
|
|
} else if (table_mode == 1) { // Grid
|
|
m_game_list_frame->hide();
|
|
m_elf_viewer->hide();
|
|
m_game_grid_frame->show();
|
|
m_dock_widget->setWidget(m_game_grid_frame.data());
|
|
slider_pos = Config::getSliderPositionGrid();
|
|
ui->sizeSlider->setSliderPosition(slider_pos); // set slider pos at start;
|
|
isTableList = false;
|
|
} else {
|
|
m_game_list_frame->hide();
|
|
m_game_grid_frame->hide();
|
|
m_elf_viewer->show();
|
|
m_dock_widget->setWidget(m_elf_viewer.data());
|
|
isTableList = false;
|
|
}
|
|
|
|
m_dock_widget->setAllowedAreas(Qt::AllDockWidgetAreas);
|
|
m_dock_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
m_dock_widget->resize(this->width(), this->height());
|
|
addDockWidget(Qt::LeftDockWidgetArea, m_dock_widget.data());
|
|
this->setDockNestingEnabled(true);
|
|
|
|
// handle resize like this for now, we deal with it when we add more docks
|
|
connect(this, &MainWindow::WindowResized, this, [&]() {
|
|
this->resizeDocks({m_dock_widget.data()}, {this->width()}, Qt::Orientation::Horizontal);
|
|
});
|
|
}
|
|
|
|
void MainWindow::LoadGameLists() {
|
|
// Load compatibility database
|
|
if (Config::getCompatibilityEnabled())
|
|
m_compat_info->LoadCompatibilityFile();
|
|
|
|
// Update compatibility database
|
|
if (Config::getCheckCompatibilityOnStartup())
|
|
m_compat_info->UpdateCompatibilityDatabase(this);
|
|
|
|
// Get game info from game folders.
|
|
m_game_info->GetGameInfo(this);
|
|
if (isTableList) {
|
|
m_game_list_frame->PopulateGameList();
|
|
} else {
|
|
m_game_grid_frame->PopulateGameGrid(m_game_info->m_games, false);
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_UPDATER
|
|
void MainWindow::CheckUpdateMain(bool checkSave) {
|
|
if (checkSave) {
|
|
if (!Config::autoUpdate()) {
|
|
return;
|
|
}
|
|
}
|
|
auto checkUpdate = new CheckUpdate(false);
|
|
checkUpdate->exec();
|
|
}
|
|
#endif
|
|
|
|
void MainWindow::GetPhysicalDevices() {
|
|
Vulkan::Instance instance(false, false);
|
|
auto physical_devices = instance.GetPhysicalDevices();
|
|
for (const vk::PhysicalDevice physical_device : physical_devices) {
|
|
auto prop = physical_device.getProperties();
|
|
QString name = QString::fromUtf8(prop.deviceName, -1);
|
|
if (prop.apiVersion < Vulkan::TargetVulkanApiVersion) {
|
|
name += tr(" * Unsupported Vulkan Version");
|
|
}
|
|
m_physical_devices.push_back(name);
|
|
}
|
|
}
|
|
|
|
void MainWindow::CreateConnects() {
|
|
connect(this, &MainWindow::WindowResized, this, &MainWindow::HandleResize);
|
|
connect(ui->mw_searchbar, &QLineEdit::textChanged, this, &MainWindow::SearchGameTable);
|
|
connect(ui->exitAct, &QAction::triggered, this, &QWidget::close);
|
|
connect(ui->refreshGameListAct, &QAction::triggered, this, &MainWindow::RefreshGameTable);
|
|
connect(ui->refreshButton, &QPushButton::clicked, this, &MainWindow::RefreshGameTable);
|
|
connect(ui->showGameListAct, &QAction::triggered, this, &MainWindow::ShowGameList);
|
|
connect(this, &MainWindow::ExtractionFinished, this, &MainWindow::RefreshGameTable);
|
|
connect(ui->toggleLabelsAct, &QAction::toggled, this, &MainWindow::toggleLabelsUnderIcons);
|
|
connect(ui->fullscreenButton, &QPushButton::clicked, this, &MainWindow::toggleFullscreen);
|
|
|
|
connect(ui->sizeSlider, &QSlider::valueChanged, this, [this](int value) {
|
|
if (isTableList) {
|
|
m_game_list_frame->icon_size =
|
|
36 + value; // 36 is the minimum icon size to use due to text disappearing.
|
|
m_game_list_frame->ResizeIcons(36 + value);
|
|
Config::setIconSize(36 + value);
|
|
Config::setSliderPosition(value);
|
|
} else {
|
|
m_game_grid_frame->icon_size = 69 + value;
|
|
m_game_grid_frame->PopulateGameGrid(m_game_info->m_games, false);
|
|
Config::setIconSizeGrid(69 + value);
|
|
Config::setSliderPositionGrid(value);
|
|
}
|
|
});
|
|
|
|
connect(ui->shadFolderAct, &QAction::triggered, this, [this]() {
|
|
QString userPath;
|
|
Common::FS::PathToQString(userPath, Common::FS::GetUserPath(Common::FS::PathType::UserDir));
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(userPath));
|
|
});
|
|
|
|
connect(ui->playButton, &QPushButton::clicked, this, &MainWindow::StartGame);
|
|
connect(ui->pauseButton, &QPushButton::clicked, this, &MainWindow::PauseGame);
|
|
connect(m_game_grid_frame.get(), &QTableWidget::cellDoubleClicked, this,
|
|
&MainWindow::StartGame);
|
|
connect(m_game_list_frame.get(), &QTableWidget::cellDoubleClicked, this,
|
|
&MainWindow::StartGame);
|
|
|
|
connect(ui->configureAct, &QAction::triggered, this, [this]() {
|
|
auto settingsDialog = new SettingsDialog(m_physical_devices, m_compat_info, this);
|
|
|
|
connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
|
|
&MainWindow::OnLanguageChanged);
|
|
|
|
connect(settingsDialog, &SettingsDialog::CompatibilityChanged, this,
|
|
&MainWindow::RefreshGameTable);
|
|
|
|
connect(settingsDialog, &SettingsDialog::accepted, this, &MainWindow::RefreshGameTable);
|
|
connect(settingsDialog, &SettingsDialog::rejected, this, &MainWindow::RefreshGameTable);
|
|
connect(settingsDialog, &SettingsDialog::close, this, &MainWindow::RefreshGameTable);
|
|
|
|
connect(settingsDialog, &SettingsDialog::BackgroundOpacityChanged, this,
|
|
[this](int opacity) {
|
|
Config::setBackgroundImageOpacity(opacity);
|
|
if (m_game_list_frame) {
|
|
QTableWidgetItem* current = m_game_list_frame->GetCurrentItem();
|
|
if (current) {
|
|
m_game_list_frame->SetListBackgroundImage(current);
|
|
}
|
|
}
|
|
if (m_game_grid_frame) {
|
|
if (m_game_grid_frame->IsValidCellSelected()) {
|
|
m_game_grid_frame->SetGridBackgroundImage(m_game_grid_frame->crtRow,
|
|
m_game_grid_frame->crtColumn);
|
|
}
|
|
}
|
|
});
|
|
|
|
settingsDialog->exec();
|
|
});
|
|
|
|
connect(ui->settingsButton, &QPushButton::clicked, this, [this]() {
|
|
auto settingsDialog = new SettingsDialog(m_physical_devices, m_compat_info, this);
|
|
|
|
connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
|
|
&MainWindow::OnLanguageChanged);
|
|
|
|
connect(settingsDialog, &SettingsDialog::CompatibilityChanged, this,
|
|
&MainWindow::RefreshGameTable);
|
|
|
|
connect(settingsDialog, &SettingsDialog::accepted, this, &MainWindow::RefreshGameTable);
|
|
connect(settingsDialog, &SettingsDialog::rejected, this, &MainWindow::RefreshGameTable);
|
|
connect(settingsDialog, &SettingsDialog::close, this, &MainWindow::RefreshGameTable);
|
|
|
|
connect(settingsDialog, &SettingsDialog::BackgroundOpacityChanged, this,
|
|
[this](int opacity) {
|
|
Config::setBackgroundImageOpacity(opacity);
|
|
if (m_game_list_frame) {
|
|
QTableWidgetItem* current = m_game_list_frame->GetCurrentItem();
|
|
if (current) {
|
|
m_game_list_frame->SetListBackgroundImage(current);
|
|
}
|
|
}
|
|
if (m_game_grid_frame) {
|
|
if (m_game_grid_frame->IsValidCellSelected()) {
|
|
m_game_grid_frame->SetGridBackgroundImage(m_game_grid_frame->crtRow,
|
|
m_game_grid_frame->crtColumn);
|
|
}
|
|
}
|
|
});
|
|
|
|
settingsDialog->exec();
|
|
});
|
|
|
|
connect(ui->controllerButton, &QPushButton::clicked, this, [this]() {
|
|
auto configWindow = new ControlSettings(m_game_info, this);
|
|
configWindow->exec();
|
|
});
|
|
|
|
connect(ui->keyboardButton, &QPushButton::clicked, this, [this]() {
|
|
auto kbmWindow = new KBMSettings(m_game_info, this);
|
|
kbmWindow->exec();
|
|
});
|
|
|
|
#ifdef ENABLE_UPDATER
|
|
connect(ui->updaterAct, &QAction::triggered, this, [this]() {
|
|
auto checkUpdate = new CheckUpdate(true);
|
|
checkUpdate->exec();
|
|
});
|
|
#endif
|
|
|
|
connect(ui->aboutAct, &QAction::triggered, this, [this]() {
|
|
auto aboutDialog = new AboutDialog(this);
|
|
aboutDialog->exec();
|
|
});
|
|
|
|
connect(ui->setIconSizeTinyAct, &QAction::triggered, this, [this]() {
|
|
if (isTableList) {
|
|
m_game_list_frame->icon_size =
|
|
36; // 36 is the minimum icon size to use due to text disappearing.
|
|
ui->sizeSlider->setValue(0); // icone_size - 36
|
|
Config::setIconSize(36);
|
|
Config::setSliderPosition(0);
|
|
} else {
|
|
ui->sizeSlider->setValue(0); // icone_size - 36
|
|
Config::setIconSizeGrid(69);
|
|
Config::setSliderPositionGrid(0);
|
|
}
|
|
});
|
|
|
|
connect(ui->setIconSizeSmallAct, &QAction::triggered, this, [this]() {
|
|
if (isTableList) {
|
|
m_game_list_frame->icon_size = 64;
|
|
ui->sizeSlider->setValue(28);
|
|
Config::setIconSize(64);
|
|
Config::setSliderPosition(28);
|
|
} else {
|
|
ui->sizeSlider->setValue(28);
|
|
Config::setIconSizeGrid(97);
|
|
Config::setSliderPositionGrid(28);
|
|
}
|
|
});
|
|
|
|
connect(ui->setIconSizeMediumAct, &QAction::triggered, this, [this]() {
|
|
if (isTableList) {
|
|
m_game_list_frame->icon_size = 128;
|
|
ui->sizeSlider->setValue(92);
|
|
Config::setIconSize(128);
|
|
Config::setSliderPosition(92);
|
|
} else {
|
|
ui->sizeSlider->setValue(92);
|
|
Config::setIconSizeGrid(160);
|
|
Config::setSliderPositionGrid(91);
|
|
}
|
|
});
|
|
|
|
connect(ui->setIconSizeLargeAct, &QAction::triggered, this, [this]() {
|
|
if (isTableList) {
|
|
m_game_list_frame->icon_size = 256;
|
|
ui->sizeSlider->setValue(220);
|
|
Config::setIconSize(256);
|
|
Config::setSliderPosition(220);
|
|
} else {
|
|
ui->sizeSlider->setValue(220);
|
|
Config::setIconSizeGrid(256);
|
|
Config::setSliderPositionGrid(220);
|
|
}
|
|
});
|
|
// List
|
|
connect(ui->setlistModeListAct, &QAction::triggered, m_dock_widget.data(), [this]() {
|
|
BackgroundMusicPlayer::getInstance().stopMusic();
|
|
m_dock_widget->setWidget(m_game_list_frame.data());
|
|
m_game_grid_frame->hide();
|
|
m_elf_viewer->hide();
|
|
m_game_list_frame->show();
|
|
if (m_game_list_frame->item(0, 0) == nullptr) {
|
|
m_game_list_frame->clearContents();
|
|
m_game_list_frame->PopulateGameList();
|
|
}
|
|
isTableList = true;
|
|
Config::setTableMode(0);
|
|
int slider_pos = Config::getSliderPosition();
|
|
ui->sizeSlider->setEnabled(true);
|
|
ui->sizeSlider->setSliderPosition(slider_pos);
|
|
ui->mw_searchbar->setText("");
|
|
});
|
|
// Grid
|
|
connect(ui->setlistModeGridAct, &QAction::triggered, m_dock_widget.data(), [this]() {
|
|
BackgroundMusicPlayer::getInstance().stopMusic();
|
|
m_dock_widget->setWidget(m_game_grid_frame.data());
|
|
m_game_grid_frame->show();
|
|
m_game_list_frame->hide();
|
|
m_elf_viewer->hide();
|
|
if (m_game_grid_frame->item(0, 0) == nullptr) {
|
|
m_game_grid_frame->clearContents();
|
|
m_game_grid_frame->PopulateGameGrid(m_game_info->m_games, false);
|
|
}
|
|
isTableList = false;
|
|
Config::setTableMode(1);
|
|
int slider_pos_grid = Config::getSliderPositionGrid();
|
|
ui->sizeSlider->setEnabled(true);
|
|
ui->sizeSlider->setSliderPosition(slider_pos_grid);
|
|
ui->mw_searchbar->setText("");
|
|
});
|
|
// Elf Viewer
|
|
connect(ui->setlistElfAct, &QAction::triggered, m_dock_widget.data(), [this]() {
|
|
BackgroundMusicPlayer::getInstance().stopMusic();
|
|
m_dock_widget->setWidget(m_elf_viewer.data());
|
|
m_game_grid_frame->hide();
|
|
m_game_list_frame->hide();
|
|
m_elf_viewer->show();
|
|
isTableList = false;
|
|
ui->sizeSlider->setDisabled(true);
|
|
Config::setTableMode(2);
|
|
});
|
|
|
|
// Cheats/Patches Download.
|
|
connect(ui->downloadCheatsPatchesAct, &QAction::triggered, this, [this]() {
|
|
QDialog* panelDialog = new QDialog(this);
|
|
QVBoxLayout* layout = new QVBoxLayout(panelDialog);
|
|
QPushButton* downloadAllCheatsButton =
|
|
new QPushButton(tr("Download Cheats For All Installed Games"), panelDialog);
|
|
QPushButton* downloadAllPatchesButton =
|
|
new QPushButton(tr("Download Patches For All Games"), panelDialog);
|
|
|
|
layout->addWidget(downloadAllCheatsButton);
|
|
layout->addWidget(downloadAllPatchesButton);
|
|
|
|
panelDialog->setLayout(layout);
|
|
|
|
connect(downloadAllCheatsButton, &QPushButton::clicked, this, [this, panelDialog]() {
|
|
QEventLoop eventLoop;
|
|
int pendingDownloads = 0;
|
|
|
|
auto onDownloadFinished = [&]() {
|
|
if (--pendingDownloads <= 0) {
|
|
eventLoop.quit();
|
|
}
|
|
};
|
|
|
|
for (const GameInfo& game : m_game_info->m_games) {
|
|
QString empty = "";
|
|
QString gameSerial = QString::fromStdString(game.serial);
|
|
QString gameVersion = QString::fromStdString(game.version);
|
|
|
|
CheatsPatches* cheatsPatches =
|
|
new CheatsPatches(empty, empty, empty, empty, empty, nullptr);
|
|
connect(cheatsPatches, &CheatsPatches::downloadFinished, onDownloadFinished);
|
|
|
|
pendingDownloads += 3;
|
|
|
|
cheatsPatches->downloadCheats("wolf2022", gameSerial, gameVersion, false);
|
|
cheatsPatches->downloadCheats("GoldHEN", gameSerial, gameVersion, false);
|
|
cheatsPatches->downloadCheats("shadPS4", gameSerial, gameVersion, false);
|
|
}
|
|
eventLoop.exec();
|
|
|
|
QMessageBox::information(
|
|
nullptr, tr("Download Complete"),
|
|
tr("You have downloaded cheats for all the games you have installed."));
|
|
|
|
panelDialog->accept();
|
|
});
|
|
connect(downloadAllPatchesButton, &QPushButton::clicked, [panelDialog]() {
|
|
QEventLoop eventLoop;
|
|
int pendingDownloads = 0;
|
|
|
|
auto onDownloadFinished = [&]() {
|
|
if (--pendingDownloads <= 0) {
|
|
eventLoop.quit();
|
|
}
|
|
};
|
|
|
|
QString empty = "";
|
|
CheatsPatches* cheatsPatches =
|
|
new CheatsPatches(empty, empty, empty, empty, empty, nullptr);
|
|
connect(cheatsPatches, &CheatsPatches::downloadFinished, onDownloadFinished);
|
|
|
|
pendingDownloads += 2;
|
|
|
|
cheatsPatches->downloadPatches("GoldHEN", false);
|
|
cheatsPatches->downloadPatches("shadPS4", false);
|
|
|
|
eventLoop.exec();
|
|
QMessageBox::information(
|
|
nullptr, tr("Download Complete"),
|
|
QString(tr("Patches Downloaded Successfully!") + "\n" +
|
|
tr("All Patches available for all games have been downloaded.")));
|
|
cheatsPatches->createFilesJson("GoldHEN");
|
|
cheatsPatches->createFilesJson("shadPS4");
|
|
panelDialog->accept();
|
|
});
|
|
panelDialog->exec();
|
|
});
|
|
|
|
// Dump game list.
|
|
connect(ui->dumpGameListAct, &QAction::triggered, this, [&] {
|
|
QString filePath = qApp->applicationDirPath().append("/GameList.txt");
|
|
QFile file(filePath);
|
|
QTextStream out(&file);
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
|
qDebug() << "Failed to open file for writing:" << file.errorString();
|
|
return;
|
|
}
|
|
out << QString("%1 %2 %3 %4 %5\n")
|
|
.arg(" NAME", -50)
|
|
.arg(" ID", -10)
|
|
.arg("FW", -4)
|
|
.arg(" APP VERSION", -11)
|
|
.arg(" Path");
|
|
for (const GameInfo& game : m_game_info->m_games) {
|
|
QString game_path;
|
|
Common::FS::PathToQString(game_path, game.path);
|
|
out << QString("%1 %2 %3 %4 %5\n")
|
|
.arg(QString::fromStdString(game.name), -50)
|
|
.arg(QString::fromStdString(game.serial), -10)
|
|
.arg(QString::fromStdString(game.fw), -4)
|
|
.arg(QString::fromStdString(game.version), -11)
|
|
.arg(game_path);
|
|
}
|
|
});
|
|
|
|
// Package install.
|
|
connect(ui->bootGameAct, &QAction::triggered, this, &MainWindow::BootGame);
|
|
connect(ui->gameInstallPathAct, &QAction::triggered, this, &MainWindow::InstallDirectory);
|
|
|
|
// elf viewer
|
|
connect(ui->addElfFolderAct, &QAction::triggered, m_elf_viewer.data(),
|
|
&ElfViewer::OpenElfFolder);
|
|
|
|
// Trophy Viewer
|
|
connect(ui->trophyViewerAct, &QAction::triggered, this, [this]() {
|
|
if (m_game_info->m_games.empty()) {
|
|
QMessageBox::information(
|
|
this, tr("Trophy Viewer"),
|
|
tr("No games found. Please add your games to your library first."));
|
|
return;
|
|
}
|
|
|
|
const auto& firstGame = m_game_info->m_games[0];
|
|
QString trophyPath, gameTrpPath;
|
|
Common::FS::PathToQString(trophyPath, firstGame.serial);
|
|
Common::FS::PathToQString(gameTrpPath, firstGame.path);
|
|
|
|
auto game_update_path = Common::FS::PathFromQString(gameTrpPath);
|
|
game_update_path += "-UPDATE";
|
|
if (std::filesystem::exists(game_update_path)) {
|
|
Common::FS::PathToQString(gameTrpPath, game_update_path);
|
|
} else {
|
|
game_update_path = Common::FS::PathFromQString(gameTrpPath);
|
|
game_update_path += "-patch";
|
|
if (std::filesystem::exists(game_update_path)) {
|
|
Common::FS::PathToQString(gameTrpPath, game_update_path);
|
|
}
|
|
}
|
|
|
|
QVector<TrophyGameInfo> allTrophyGames;
|
|
for (const auto& game : m_game_info->m_games) {
|
|
TrophyGameInfo gameInfo;
|
|
gameInfo.name = QString::fromStdString(game.name);
|
|
Common::FS::PathToQString(gameInfo.trophyPath, game.serial);
|
|
Common::FS::PathToQString(gameInfo.gameTrpPath, game.path);
|
|
|
|
auto update_path = Common::FS::PathFromQString(gameInfo.gameTrpPath);
|
|
update_path += "-UPDATE";
|
|
if (std::filesystem::exists(update_path)) {
|
|
Common::FS::PathToQString(gameInfo.gameTrpPath, update_path);
|
|
} else {
|
|
update_path = Common::FS::PathFromQString(gameInfo.gameTrpPath);
|
|
update_path += "-patch";
|
|
if (std::filesystem::exists(update_path)) {
|
|
Common::FS::PathToQString(gameInfo.gameTrpPath, update_path);
|
|
}
|
|
}
|
|
|
|
allTrophyGames.append(gameInfo);
|
|
}
|
|
|
|
QString gameName = QString::fromStdString(firstGame.name);
|
|
TrophyViewer* trophyViewer =
|
|
new TrophyViewer(trophyPath, gameTrpPath, gameName, allTrophyGames);
|
|
trophyViewer->show();
|
|
});
|
|
|
|
// Themes
|
|
connect(ui->setThemeDark, &QAction::triggered, &m_window_themes, [this]() {
|
|
m_window_themes.SetWindowTheme(Theme::Dark, ui->mw_searchbar);
|
|
Config::setMainWindowTheme(static_cast<int>(Theme::Dark));
|
|
if (isIconBlack) {
|
|
SetUiIcons(false);
|
|
isIconBlack = false;
|
|
}
|
|
});
|
|
connect(ui->setThemeLight, &QAction::triggered, &m_window_themes, [this]() {
|
|
m_window_themes.SetWindowTheme(Theme::Light, ui->mw_searchbar);
|
|
Config::setMainWindowTheme(static_cast<int>(Theme::Light));
|
|
if (!isIconBlack) {
|
|
SetUiIcons(true);
|
|
isIconBlack = true;
|
|
}
|
|
});
|
|
connect(ui->setThemeGreen, &QAction::triggered, &m_window_themes, [this]() {
|
|
m_window_themes.SetWindowTheme(Theme::Green, ui->mw_searchbar);
|
|
Config::setMainWindowTheme(static_cast<int>(Theme::Green));
|
|
if (isIconBlack) {
|
|
SetUiIcons(false);
|
|
isIconBlack = false;
|
|
}
|
|
});
|
|
connect(ui->setThemeBlue, &QAction::triggered, &m_window_themes, [this]() {
|
|
m_window_themes.SetWindowTheme(Theme::Blue, ui->mw_searchbar);
|
|
Config::setMainWindowTheme(static_cast<int>(Theme::Blue));
|
|
if (isIconBlack) {
|
|
SetUiIcons(false);
|
|
isIconBlack = false;
|
|
}
|
|
});
|
|
connect(ui->setThemeViolet, &QAction::triggered, &m_window_themes, [this]() {
|
|
m_window_themes.SetWindowTheme(Theme::Violet, ui->mw_searchbar);
|
|
Config::setMainWindowTheme(static_cast<int>(Theme::Violet));
|
|
if (isIconBlack) {
|
|
SetUiIcons(false);
|
|
isIconBlack = false;
|
|
}
|
|
});
|
|
connect(ui->setThemeGruvbox, &QAction::triggered, &m_window_themes, [this]() {
|
|
m_window_themes.SetWindowTheme(Theme::Gruvbox, ui->mw_searchbar);
|
|
Config::setMainWindowTheme(static_cast<int>(Theme::Gruvbox));
|
|
if (isIconBlack) {
|
|
SetUiIcons(false);
|
|
isIconBlack = false;
|
|
}
|
|
});
|
|
connect(ui->setThemeTokyoNight, &QAction::triggered, &m_window_themes, [this]() {
|
|
m_window_themes.SetWindowTheme(Theme::TokyoNight, ui->mw_searchbar);
|
|
Config::setMainWindowTheme(static_cast<int>(Theme::TokyoNight));
|
|
if (isIconBlack) {
|
|
SetUiIcons(false);
|
|
isIconBlack = false;
|
|
}
|
|
});
|
|
connect(ui->setThemeOled, &QAction::triggered, &m_window_themes, [this]() {
|
|
m_window_themes.SetWindowTheme(Theme::Oled, ui->mw_searchbar);
|
|
Config::setMainWindowTheme(static_cast<int>(Theme::Oled));
|
|
if (isIconBlack) {
|
|
SetUiIcons(false);
|
|
isIconBlack = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
void MainWindow::StartGame() {
|
|
BackgroundMusicPlayer::getInstance().stopMusic();
|
|
QString gamePath = "";
|
|
int table_mode = Config::getTableMode();
|
|
if (table_mode == 0) {
|
|
if (m_game_list_frame->currentItem()) {
|
|
int itemID = m_game_list_frame->currentItem()->row();
|
|
Common::FS::PathToQString(gamePath, m_game_info->m_games[itemID].path / "eboot.bin");
|
|
}
|
|
} else if (table_mode == 1) {
|
|
if (m_game_grid_frame->cellClicked) {
|
|
int itemID = (m_game_grid_frame->crtRow * m_game_grid_frame->columnCnt) +
|
|
m_game_grid_frame->crtColumn;
|
|
Common::FS::PathToQString(gamePath, m_game_info->m_games[itemID].path / "eboot.bin");
|
|
}
|
|
} else {
|
|
if (m_elf_viewer->currentItem()) {
|
|
int itemID = m_elf_viewer->currentItem()->row();
|
|
gamePath = m_elf_viewer->m_elf_list[itemID];
|
|
}
|
|
}
|
|
if (gamePath != "") {
|
|
AddRecentFiles(gamePath);
|
|
const auto path = Common::FS::PathFromQString(gamePath);
|
|
if (!std::filesystem::exists(path)) {
|
|
QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Eboot.bin file not found")));
|
|
return;
|
|
}
|
|
StartEmulator(path);
|
|
|
|
UpdateToolbarButtons();
|
|
}
|
|
}
|
|
|
|
bool isTable;
|
|
void MainWindow::SearchGameTable(const QString& text) {
|
|
if (isTableList) {
|
|
if (isTable != true) {
|
|
m_game_info->m_games = m_game_info->m_games_backup;
|
|
m_game_list_frame->PopulateGameList();
|
|
isTable = true;
|
|
}
|
|
for (int row = 0; row < m_game_list_frame->rowCount(); row++) {
|
|
QString game_name = QString::fromStdString(m_game_info->m_games[row].name);
|
|
bool match = (game_name.contains(text, Qt::CaseInsensitive)); // Check only in column 1
|
|
m_game_list_frame->setRowHidden(row, !match);
|
|
}
|
|
} else {
|
|
isTable = false;
|
|
m_game_info->m_games = m_game_info->m_games_backup;
|
|
m_game_grid_frame->PopulateGameGrid(m_game_info->m_games, false);
|
|
|
|
QVector<GameInfo> filteredGames;
|
|
for (const auto& gameInfo : m_game_info->m_games) {
|
|
QString game_name = QString::fromStdString(gameInfo.name);
|
|
if (game_name.contains(text, Qt::CaseInsensitive)) {
|
|
filteredGames.push_back(gameInfo);
|
|
}
|
|
}
|
|
std::sort(filteredGames.begin(), filteredGames.end(), m_game_info->CompareStrings);
|
|
m_game_info->m_games = filteredGames;
|
|
m_game_grid_frame->PopulateGameGrid(filteredGames, true);
|
|
}
|
|
}
|
|
|
|
void MainWindow::ShowGameList() {
|
|
if (ui->showGameListAct->isChecked()) {
|
|
RefreshGameTable();
|
|
} else {
|
|
m_game_grid_frame->clearContents();
|
|
m_game_list_frame->clearContents();
|
|
}
|
|
};
|
|
|
|
void MainWindow::RefreshGameTable() {
|
|
// m_game_info->m_games.clear();
|
|
m_game_info->GetGameInfo(this);
|
|
m_game_list_frame->clearContents();
|
|
m_game_list_frame->PopulateGameList();
|
|
m_game_grid_frame->clearContents();
|
|
m_game_grid_frame->PopulateGameGrid(m_game_info->m_games, false);
|
|
statusBar->clearMessage();
|
|
int numGames = m_game_info->m_games.size();
|
|
QString statusMessage = tr("Games: ") + QString::number(numGames);
|
|
statusBar->showMessage(statusMessage);
|
|
}
|
|
|
|
void MainWindow::ConfigureGuiFromSettings() {
|
|
setGeometry(Config::getMainWindowGeometryX(), Config::getMainWindowGeometryY(),
|
|
Config::getMainWindowGeometryW(), Config::getMainWindowGeometryH());
|
|
|
|
ui->showGameListAct->setChecked(true);
|
|
if (Config::getTableMode() == 0) {
|
|
ui->setlistModeListAct->setChecked(true);
|
|
} else if (Config::getTableMode() == 1) {
|
|
ui->setlistModeGridAct->setChecked(true);
|
|
} else if (Config::getTableMode() == 2) {
|
|
ui->setlistElfAct->setChecked(true);
|
|
}
|
|
BackgroundMusicPlayer::getInstance().setVolume(Config::getBGMvolume());
|
|
}
|
|
|
|
void MainWindow::SaveWindowState() const {
|
|
Config::setMainWindowWidth(this->width());
|
|
Config::setMainWindowHeight(this->height());
|
|
Config::setMainWindowGeometry(this->geometry().x(), this->geometry().y(),
|
|
this->geometry().width(), this->geometry().height());
|
|
}
|
|
|
|
void MainWindow::BootGame() {
|
|
QFileDialog dialog;
|
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
|
dialog.setNameFilter(tr("ELF files (*.bin *.elf *.oelf)"));
|
|
if (dialog.exec()) {
|
|
QStringList fileNames = dialog.selectedFiles();
|
|
int nFiles = fileNames.size();
|
|
|
|
if (nFiles > 1) {
|
|
QMessageBox::critical(nullptr, tr("Game Boot"),
|
|
QString(tr("Only one file can be selected!")));
|
|
} else {
|
|
std::filesystem::path path = Common::FS::PathFromQString(fileNames[0]);
|
|
if (!std::filesystem::exists(path)) {
|
|
QMessageBox::critical(nullptr, tr("Run Game"),
|
|
QString(tr("Eboot.bin file not found")));
|
|
return;
|
|
}
|
|
StartEmulator(path);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::InstallDirectory() {
|
|
GameInstallDialog dlg;
|
|
dlg.exec();
|
|
RefreshGameTable();
|
|
}
|
|
|
|
void MainWindow::SetLastUsedTheme() {
|
|
Theme lastTheme = static_cast<Theme>(Config::getMainWindowTheme());
|
|
m_window_themes.SetWindowTheme(lastTheme, ui->mw_searchbar);
|
|
|
|
switch (lastTheme) {
|
|
case Theme::Light:
|
|
ui->setThemeLight->setChecked(true);
|
|
isIconBlack = true;
|
|
break;
|
|
case Theme::Dark:
|
|
ui->setThemeDark->setChecked(true);
|
|
isIconBlack = false;
|
|
SetUiIcons(false);
|
|
break;
|
|
case Theme::Green:
|
|
ui->setThemeGreen->setChecked(true);
|
|
isIconBlack = false;
|
|
SetUiIcons(false);
|
|
break;
|
|
case Theme::Blue:
|
|
ui->setThemeBlue->setChecked(true);
|
|
isIconBlack = false;
|
|
SetUiIcons(false);
|
|
break;
|
|
case Theme::Violet:
|
|
ui->setThemeViolet->setChecked(true);
|
|
isIconBlack = false;
|
|
SetUiIcons(false);
|
|
break;
|
|
case Theme::Gruvbox:
|
|
ui->setThemeGruvbox->setChecked(true);
|
|
isIconBlack = false;
|
|
SetUiIcons(false);
|
|
break;
|
|
case Theme::TokyoNight:
|
|
ui->setThemeTokyoNight->setChecked(true);
|
|
isIconBlack = false;
|
|
SetUiIcons(false);
|
|
break;
|
|
case Theme::Oled:
|
|
ui->setThemeOled->setChecked(true);
|
|
isIconBlack = false;
|
|
SetUiIcons(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MainWindow::SetLastIconSizeBullet() {
|
|
// set QAction bullet point if applicable
|
|
int lastSize = Config::getIconSize();
|
|
switch (lastSize) {
|
|
case 36:
|
|
ui->setIconSizeTinyAct->setChecked(true);
|
|
break;
|
|
case 64:
|
|
ui->setIconSizeSmallAct->setChecked(true);
|
|
break;
|
|
case 128:
|
|
ui->setIconSizeMediumAct->setChecked(true);
|
|
break;
|
|
case 256:
|
|
ui->setIconSizeLargeAct->setChecked(true);
|
|
break;
|
|
}
|
|
}
|
|
|
|
QIcon MainWindow::RecolorIcon(const QIcon& icon, bool isWhite) {
|
|
QPixmap pixmap(icon.pixmap(icon.actualSize(QSize(120, 120))));
|
|
QColor clr(isWhite ? Qt::white : Qt::black);
|
|
QBitmap mask = pixmap.createMaskFromColor(clr, Qt::MaskOutColor);
|
|
pixmap.fill(QColor(isWhite ? Qt::black : Qt::white));
|
|
pixmap.setMask(mask);
|
|
return QIcon(pixmap);
|
|
}
|
|
|
|
void MainWindow::SetUiIcons(bool isWhite) {
|
|
ui->bootGameAct->setIcon(RecolorIcon(ui->bootGameAct->icon(), isWhite));
|
|
ui->shadFolderAct->setIcon(RecolorIcon(ui->shadFolderAct->icon(), isWhite));
|
|
ui->exitAct->setIcon(RecolorIcon(ui->exitAct->icon(), isWhite));
|
|
#ifdef ENABLE_UPDATER
|
|
ui->updaterAct->setIcon(RecolorIcon(ui->updaterAct->icon(), isWhite));
|
|
#endif
|
|
ui->downloadCheatsPatchesAct->setIcon(
|
|
RecolorIcon(ui->downloadCheatsPatchesAct->icon(), isWhite));
|
|
ui->dumpGameListAct->setIcon(RecolorIcon(ui->dumpGameListAct->icon(), isWhite));
|
|
ui->aboutAct->setIcon(RecolorIcon(ui->aboutAct->icon(), isWhite));
|
|
ui->setlistModeListAct->setIcon(RecolorIcon(ui->setlistModeListAct->icon(), isWhite));
|
|
ui->setlistModeGridAct->setIcon(RecolorIcon(ui->setlistModeGridAct->icon(), isWhite));
|
|
ui->gameInstallPathAct->setIcon(RecolorIcon(ui->gameInstallPathAct->icon(), isWhite));
|
|
ui->menuThemes->setIcon(RecolorIcon(ui->menuThemes->icon(), isWhite));
|
|
ui->menuGame_List_Icons->setIcon(RecolorIcon(ui->menuGame_List_Icons->icon(), isWhite));
|
|
ui->menuUtils->setIcon(RecolorIcon(ui->menuUtils->icon(), isWhite));
|
|
ui->playButton->setIcon(RecolorIcon(ui->playButton->icon(), isWhite));
|
|
ui->pauseButton->setIcon(RecolorIcon(ui->pauseButton->icon(), isWhite));
|
|
ui->stopButton->setIcon(RecolorIcon(ui->stopButton->icon(), isWhite));
|
|
ui->refreshButton->setIcon(RecolorIcon(ui->refreshButton->icon(), isWhite));
|
|
ui->restartButton->setIcon(RecolorIcon(ui->restartButton->icon(), isWhite));
|
|
ui->settingsButton->setIcon(RecolorIcon(ui->settingsButton->icon(), isWhite));
|
|
ui->fullscreenButton->setIcon(RecolorIcon(ui->fullscreenButton->icon(), isWhite));
|
|
ui->controllerButton->setIcon(RecolorIcon(ui->controllerButton->icon(), isWhite));
|
|
ui->keyboardButton->setIcon(RecolorIcon(ui->keyboardButton->icon(), isWhite));
|
|
ui->refreshGameListAct->setIcon(RecolorIcon(ui->refreshGameListAct->icon(), isWhite));
|
|
ui->menuGame_List_Mode->setIcon(RecolorIcon(ui->menuGame_List_Mode->icon(), isWhite));
|
|
ui->trophyViewerAct->setIcon(RecolorIcon(ui->trophyViewerAct->icon(), isWhite));
|
|
ui->configureAct->setIcon(RecolorIcon(ui->configureAct->icon(), isWhite));
|
|
ui->addElfFolderAct->setIcon(RecolorIcon(ui->addElfFolderAct->icon(), isWhite));
|
|
}
|
|
|
|
void MainWindow::resizeEvent(QResizeEvent* event) {
|
|
emit WindowResized(event);
|
|
QMainWindow::resizeEvent(event);
|
|
}
|
|
|
|
void MainWindow::HandleResize(QResizeEvent* event) {
|
|
if (isTableList) {
|
|
m_game_list_frame->RefreshListBackgroundImage();
|
|
} else {
|
|
m_game_grid_frame->windowWidth = this->width();
|
|
m_game_grid_frame->PopulateGameGrid(m_game_info->m_games, false);
|
|
m_game_grid_frame->RefreshGridBackgroundImage();
|
|
}
|
|
}
|
|
|
|
void MainWindow::AddRecentFiles(QString filePath) {
|
|
std::vector<std::string> vec = Config::getRecentFiles();
|
|
if (!vec.empty()) {
|
|
if (filePath.toStdString() == vec.at(0)) {
|
|
return;
|
|
}
|
|
auto it = std::find(vec.begin(), vec.end(), filePath.toStdString());
|
|
if (it != vec.end()) {
|
|
vec.erase(it);
|
|
}
|
|
}
|
|
vec.insert(vec.begin(), filePath.toStdString());
|
|
if (vec.size() > 6) {
|
|
vec.pop_back();
|
|
}
|
|
Config::setRecentFiles(vec);
|
|
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
|
Config::saveMainWindow(config_dir / "config.toml");
|
|
CreateRecentGameActions(); // Refresh the QActions.
|
|
}
|
|
|
|
void MainWindow::CreateRecentGameActions() {
|
|
m_recent_files_group = new QActionGroup(this);
|
|
ui->menuRecent->clear();
|
|
std::vector<std::string> vec = Config::getRecentFiles();
|
|
for (int i = 0; i < vec.size(); i++) {
|
|
QAction* recentFileAct = new QAction(this);
|
|
recentFileAct->setText(QString::fromStdString(vec.at(i)));
|
|
ui->menuRecent->addAction(recentFileAct);
|
|
m_recent_files_group->addAction(recentFileAct);
|
|
}
|
|
|
|
connect(m_recent_files_group, &QActionGroup::triggered, this, [this](QAction* action) {
|
|
auto gamePath = Common::FS::PathFromQString(action->text());
|
|
AddRecentFiles(action->text()); // Update the list.
|
|
if (!std::filesystem::exists(gamePath)) {
|
|
QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Eboot.bin file not found")));
|
|
return;
|
|
}
|
|
StartEmulator(gamePath);
|
|
});
|
|
}
|
|
|
|
void MainWindow::LoadTranslation() {
|
|
auto language = QString::fromStdString(Config::getEmulatorLanguage());
|
|
|
|
const QString base_dir = QStringLiteral(":/translations");
|
|
QString base_path = QStringLiteral("%1/%2.qm").arg(base_dir).arg(language);
|
|
|
|
if (QFile::exists(base_path)) {
|
|
if (translator != nullptr) {
|
|
qApp->removeTranslator(translator);
|
|
}
|
|
|
|
translator = new QTranslator(qApp);
|
|
if (!translator->load(base_path)) {
|
|
QMessageBox::warning(
|
|
nullptr, QStringLiteral("Translation Error"),
|
|
QStringLiteral("Failed to find load translation file for '%1':\n%2")
|
|
.arg(language)
|
|
.arg(base_path));
|
|
delete translator;
|
|
} else {
|
|
qApp->installTranslator(translator);
|
|
ui->retranslateUi(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::OnLanguageChanged(const std::string& locale) {
|
|
Config::setEmulatorLanguage(locale);
|
|
|
|
LoadTranslation();
|
|
}
|
|
|
|
bool MainWindow::eventFilter(QObject* obj, QEvent* event) {
|
|
if (event->type() == QEvent::KeyPress) {
|
|
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
|
if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) {
|
|
auto tblMode = Config::getTableMode();
|
|
if (tblMode != 2 && (tblMode != 1 || m_game_grid_frame->IsValidCellSelected())) {
|
|
StartGame();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return QMainWindow::eventFilter(obj, event);
|
|
}
|
|
|
|
void MainWindow::StartEmulator(std::filesystem::path path) {
|
|
if (isGameRunning) {
|
|
QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Game is already running!")));
|
|
return;
|
|
}
|
|
isGameRunning = true;
|
|
#ifdef __APPLE__
|
|
// SDL on macOS requires main thread.
|
|
Core::Emulator emulator;
|
|
emulator.Run(path);
|
|
#else
|
|
std::thread emulator_thread([=] {
|
|
Core::Emulator emulator;
|
|
emulator.Run(path);
|
|
});
|
|
emulator_thread.detach();
|
|
#endif
|
|
}
|