mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-05 00:42:48 +00:00
Added slider to control background image opacity
This commit is contained in:
parent
bd4cd9632c
commit
681c1bbf64
@ -95,6 +95,7 @@ std::vector<std::string> m_pkg_viewer;
|
|||||||
std::vector<std::string> m_elf_viewer;
|
std::vector<std::string> m_elf_viewer;
|
||||||
std::vector<std::string> m_recent_files;
|
std::vector<std::string> m_recent_files;
|
||||||
std::string emulator_language = "en";
|
std::string emulator_language = "en";
|
||||||
|
static int backgroundImageOpacity = 50;
|
||||||
|
|
||||||
// Language
|
// Language
|
||||||
u32 m_language = 1; // english
|
u32 m_language = 1; // english
|
||||||
@ -611,6 +612,14 @@ u32 GetLanguage() {
|
|||||||
return m_language;
|
return m_language;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getBackgroundImageOpacity() {
|
||||||
|
return backgroundImageOpacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBackgroundImageOpacity(int opacity) {
|
||||||
|
backgroundImageOpacity = std::clamp(opacity, 0, 100);
|
||||||
|
}
|
||||||
|
|
||||||
void load(const std::filesystem::path& path) {
|
void load(const std::filesystem::path& path) {
|
||||||
// If the configuration file does not exist, create it and return
|
// If the configuration file does not exist, create it and return
|
||||||
std::error_code error;
|
std::error_code error;
|
||||||
@ -655,6 +664,7 @@ void load(const std::filesystem::path& path) {
|
|||||||
checkCompatibilityOnStartup =
|
checkCompatibilityOnStartup =
|
||||||
toml::find_or<bool>(general, "checkCompatibilityOnStartup", false);
|
toml::find_or<bool>(general, "checkCompatibilityOnStartup", false);
|
||||||
chooseHomeTab = toml::find_or<std::string>(general, "chooseHomeTab", "Release");
|
chooseHomeTab = toml::find_or<std::string>(general, "chooseHomeTab", "Release");
|
||||||
|
backgroundImageOpacity = toml::find_or<int>(general, "backgroundImageOpacity", 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.contains("Input")) {
|
if (data.contains("Input")) {
|
||||||
@ -783,6 +793,7 @@ void save(const std::filesystem::path& path) {
|
|||||||
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
|
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
|
||||||
data["General"]["compatibilityEnabled"] = compatibilityData;
|
data["General"]["compatibilityEnabled"] = compatibilityData;
|
||||||
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
|
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
|
||||||
|
data["General"]["backgroundImageOpacity"] = backgroundImageOpacity;
|
||||||
data["Input"]["cursorState"] = cursorState;
|
data["Input"]["cursorState"] = cursorState;
|
||||||
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
|
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
|
||||||
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
||||||
@ -914,6 +925,7 @@ void setDefaultValues() {
|
|||||||
separateupdatefolder = false;
|
separateupdatefolder = false;
|
||||||
compatibilityData = false;
|
compatibilityData = false;
|
||||||
checkCompatibilityOnStartup = false;
|
checkCompatibilityOnStartup = false;
|
||||||
|
backgroundImageOpacity = 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr std::string_view GetDefaultKeyboardConfig() {
|
constexpr std::string_view GetDefaultKeyboardConfig() {
|
||||||
|
@ -30,6 +30,7 @@ bool getEnableDiscordRPC();
|
|||||||
bool getSeparateUpdateEnabled();
|
bool getSeparateUpdateEnabled();
|
||||||
bool getCompatibilityEnabled();
|
bool getCompatibilityEnabled();
|
||||||
bool getCheckCompatibilityOnStartup();
|
bool getCheckCompatibilityOnStartup();
|
||||||
|
int getBackgroundImageOpacity();
|
||||||
|
|
||||||
std::string getLogFilter();
|
std::string getLogFilter();
|
||||||
std::string getLogType();
|
std::string getLogType();
|
||||||
@ -88,6 +89,7 @@ void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_insta
|
|||||||
void setSaveDataPath(const std::filesystem::path& path);
|
void setSaveDataPath(const std::filesystem::path& path);
|
||||||
void setCompatibilityEnabled(bool use);
|
void setCompatibilityEnabled(bool use);
|
||||||
void setCheckCompatibilityOnStartup(bool use);
|
void setCheckCompatibilityOnStartup(bool use);
|
||||||
|
void setBackgroundImageOpacity(int opacity);
|
||||||
|
|
||||||
void setCursorState(s16 cursorState);
|
void setCursorState(s16 cursorState);
|
||||||
void setCursorHideTimeout(int newcursorHideTimeout);
|
void setCursorHideTimeout(int newcursorHideTimeout);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
#include "game_grid_frame.h"
|
#include "game_grid_frame.h"
|
||||||
#include "qt_gui/compatibility_info.h"
|
#include "qt_gui/compatibility_info.h"
|
||||||
@ -153,32 +155,43 @@ void GameGridFrame::PopulateGameGrid(QVector<GameInfo> m_games_search, bool from
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GameGridFrame::SetGridBackgroundImage(int row, int column) {
|
void GameGridFrame::SetGridBackgroundImage(int row, int column) {
|
||||||
|
|
||||||
int itemID = (row * this->columnCount()) + column;
|
int itemID = (row * this->columnCount()) + column;
|
||||||
QWidget* item = this->cellWidget(row, column);
|
QWidget* item = this->cellWidget(row, column);
|
||||||
if (item) {
|
if (!item) {
|
||||||
QString pic1Path;
|
// handle case where no item was clicked
|
||||||
Common::FS::PathToQString(pic1Path, (*m_games_shared)[itemID].pic_path);
|
return;
|
||||||
const auto blurredPic1Path = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
|
||||||
(*m_games_shared)[itemID].serial / "pic1.png";
|
|
||||||
QString blurredPic1PathQt;
|
|
||||||
Common::FS::PathToQString(blurredPic1PathQt, blurredPic1Path);
|
|
||||||
|
|
||||||
backgroundImage = QImage(blurredPic1PathQt);
|
|
||||||
if (backgroundImage.isNull()) {
|
|
||||||
QImage image(pic1Path);
|
|
||||||
backgroundImage = m_game_list_utils.ChangeImageOpacity(image, image.rect(), 0.5);
|
|
||||||
|
|
||||||
std::filesystem::path img_path =
|
|
||||||
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
|
||||||
(*m_games_shared)[itemID].serial;
|
|
||||||
std::filesystem::create_directories(img_path);
|
|
||||||
if (!backgroundImage.save(blurredPic1PathQt, "PNG")) {
|
|
||||||
// qDebug() << "Error: Unable to save image.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RefreshGridBackgroundImage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& game = (*m_games_shared)[itemID];
|
||||||
|
const int opacity = Config::getBackgroundImageOpacity();
|
||||||
|
const auto cache_path = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
||||||
|
game.serial / fmt::format("pic1_{}.png", opacity);
|
||||||
|
|
||||||
|
// Fast path - try to load cached version first
|
||||||
|
if (std::filesystem::exists(cache_path)) {
|
||||||
|
backgroundImage = QImage(QString::fromStdString(cache_path.string()));
|
||||||
|
if (!backgroundImage.isNull()) {
|
||||||
|
RefreshGridBackgroundImage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache miss - generate and store
|
||||||
|
m_game_list_utils.CleanupOldOpacityImages(cache_path.parent_path());
|
||||||
|
QImage original_image(QString::fromStdString(game.pic_path.string()));
|
||||||
|
if (!original_image.isNull()) {
|
||||||
|
std::filesystem::create_directories(cache_path.parent_path());
|
||||||
|
backgroundImage = m_game_list_utils.ChangeImageOpacity(
|
||||||
|
original_image, original_image.rect(), opacity / 100.0f);
|
||||||
|
if (!backgroundImage.isNull()) {
|
||||||
|
// Save the image to the cache asynchronously
|
||||||
|
QFuture<void> future = QtConcurrent::run([this, cache_path]() {
|
||||||
|
backgroundImage.save(QString::fromStdString(cache_path.string()), "PNG");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshGridBackgroundImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameGridFrame::RefreshGridBackgroundImage() {
|
void GameGridFrame::RefreshGridBackgroundImage() {
|
||||||
|
@ -167,26 +167,35 @@ void GameListFrame::SetListBackgroundImage(QTableWidgetItem* item) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString pic1Path;
|
const auto& game = m_game_info->m_games[item->row()];
|
||||||
Common::FS::PathToQString(pic1Path, m_game_info->m_games[item->row()].pic_path);
|
const int opacity = Config::getBackgroundImageOpacity();
|
||||||
const auto blurredPic1Path = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
const auto cache_path = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
||||||
m_game_info->m_games[item->row()].serial / "pic1.png";
|
game.serial / fmt::format("pic1_{}.png", opacity);
|
||||||
QString blurredPic1PathQt;
|
|
||||||
Common::FS::PathToQString(blurredPic1PathQt, blurredPic1Path);
|
|
||||||
|
|
||||||
backgroundImage = QImage(blurredPic1PathQt);
|
// Fast path - try to load cached version first
|
||||||
if (backgroundImage.isNull()) {
|
if (std::filesystem::exists(cache_path)) {
|
||||||
QImage image(pic1Path);
|
backgroundImage = QImage(QString::fromStdString(cache_path.string()));
|
||||||
backgroundImage = m_game_list_utils.ChangeImageOpacity(image, image.rect(), 0.5);
|
if (!backgroundImage.isNull()) {
|
||||||
|
RefreshListBackgroundImage();
|
||||||
std::filesystem::path img_path =
|
return;
|
||||||
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
|
||||||
m_game_info->m_games[item->row()].serial;
|
|
||||||
std::filesystem::create_directories(img_path);
|
|
||||||
if (!backgroundImage.save(blurredPic1PathQt, "PNG")) {
|
|
||||||
// qDebug() << "Error: Unable to save image.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cache miss - generate and store
|
||||||
|
m_game_list_utils.CleanupOldOpacityImages(cache_path.parent_path());
|
||||||
|
QImage original_image(QString::fromStdString(game.pic_path.string()));
|
||||||
|
if (!original_image.isNull()) {
|
||||||
|
std::filesystem::create_directories(cache_path.parent_path());
|
||||||
|
backgroundImage = m_game_list_utils.ChangeImageOpacity(
|
||||||
|
original_image, original_image.rect(), opacity / 100.0f);
|
||||||
|
if (!backgroundImage.isNull()) {
|
||||||
|
// Save the image to the cache asynchronously
|
||||||
|
QFuture<void> future = QtConcurrent::run([this, cache_path]() {
|
||||||
|
backgroundImage.save(QString::fromStdString(cache_path.string()), "PNG");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RefreshListBackgroundImage();
|
RefreshListBackgroundImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +202,8 @@ public:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage ChangeImageOpacity(const QImage& image, const QRect& rect, float opacity) {
|
// Opacity is a float between 0 and 1
|
||||||
|
static QImage ChangeImageOpacity(const QImage& image, const QRect& rect, float opacity) {
|
||||||
// Convert to ARGB32 format to ensure alpha channel support
|
// Convert to ARGB32 format to ensure alpha channel support
|
||||||
QImage result = image.convertToFormat(QImage::Format_ARGB32);
|
QImage result = image.convertToFormat(QImage::Format_ARGB32);
|
||||||
|
|
||||||
@ -226,4 +227,17 @@ public:
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CleanupOldOpacityImages(const std::filesystem::path& dir) {
|
||||||
|
if (!std::filesystem::exists(dir)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& entry : std::filesystem::directory_iterator(dir)) {
|
||||||
|
const auto& path = entry.path();
|
||||||
|
if (path.filename().string().starts_with("pic1") && path.extension() == ".png") {
|
||||||
|
std::filesystem::remove(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -173,6 +173,10 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
|||||||
{
|
{
|
||||||
connect(ui->chooseHomeTabComboBox, &QComboBox::currentTextChanged, this,
|
connect(ui->chooseHomeTabComboBox, &QComboBox::currentTextChanged, this,
|
||||||
[](const QString& hometab) { Config::setChooseHomeTab(hometab.toStdString()); });
|
[](const QString& hometab) { Config::setChooseHomeTab(hometab.toStdString()); });
|
||||||
|
|
||||||
|
// Add background image opacity slider connection
|
||||||
|
connect(ui->backgroundImageOpacitySlider, &QSlider::valueChanged, this,
|
||||||
|
[](int value) { Config::setBackgroundImageOpacity(value); });
|
||||||
}
|
}
|
||||||
// Input TAB
|
// Input TAB
|
||||||
{
|
{
|
||||||
@ -251,6 +255,7 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
|||||||
#ifdef ENABLE_UPDATER
|
#ifdef ENABLE_UPDATER
|
||||||
ui->updaterGroupBox->installEventFilter(this);
|
ui->updaterGroupBox->installEventFilter(this);
|
||||||
#endif
|
#endif
|
||||||
|
ui->GUIBackgroundImageGroupBox->installEventFilter(this);
|
||||||
ui->GUIMusicGroupBox->installEventFilter(this);
|
ui->GUIMusicGroupBox->installEventFilter(this);
|
||||||
ui->disableTrophycheckBox->installEventFilter(this);
|
ui->disableTrophycheckBox->installEventFilter(this);
|
||||||
ui->enableCompatibilityCheckBox->installEventFilter(this);
|
ui->enableCompatibilityCheckBox->installEventFilter(this);
|
||||||
@ -410,6 +415,7 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||||||
|
|
||||||
ui->removeFolderButton->setEnabled(!ui->gameFoldersListWidget->selectedItems().isEmpty());
|
ui->removeFolderButton->setEnabled(!ui->gameFoldersListWidget->selectedItems().isEmpty());
|
||||||
ResetInstallFolders();
|
ResetInstallFolders();
|
||||||
|
ui->backgroundImageOpacitySlider->setValue(Config::getBackgroundImageOpacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::InitializeEmulatorLanguages() {
|
void SettingsDialog::InitializeEmulatorLanguages() {
|
||||||
@ -504,6 +510,8 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
|||||||
} else if (elementName == "updaterGroupBox") {
|
} else if (elementName == "updaterGroupBox") {
|
||||||
text = tr("updaterGroupBox");
|
text = tr("updaterGroupBox");
|
||||||
#endif
|
#endif
|
||||||
|
} else if (elementName == "GUIBackgroundImageGroupBox") {
|
||||||
|
text = tr("GUIBackgroundImageGroupBox");
|
||||||
} else if (elementName == "GUIMusicGroupBox") {
|
} else if (elementName == "GUIMusicGroupBox") {
|
||||||
text = tr("GUIMusicGroupBox");
|
text = tr("GUIMusicGroupBox");
|
||||||
} else if (elementName == "disableTrophycheckBox") {
|
} else if (elementName == "disableTrophycheckBox") {
|
||||||
|
Loading…
Reference in New Issue
Block a user