mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 16:32:39 +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_recent_files;
|
||||
std::string emulator_language = "en";
|
||||
static int backgroundImageOpacity = 50;
|
||||
|
||||
// Language
|
||||
u32 m_language = 1; // english
|
||||
@ -611,6 +612,14 @@ u32 GetLanguage() {
|
||||
return m_language;
|
||||
}
|
||||
|
||||
int getBackgroundImageOpacity() {
|
||||
return backgroundImageOpacity;
|
||||
}
|
||||
|
||||
void setBackgroundImageOpacity(int opacity) {
|
||||
backgroundImageOpacity = std::clamp(opacity, 0, 100);
|
||||
}
|
||||
|
||||
void load(const std::filesystem::path& path) {
|
||||
// If the configuration file does not exist, create it and return
|
||||
std::error_code error;
|
||||
@ -655,6 +664,7 @@ void load(const std::filesystem::path& path) {
|
||||
checkCompatibilityOnStartup =
|
||||
toml::find_or<bool>(general, "checkCompatibilityOnStartup", false);
|
||||
chooseHomeTab = toml::find_or<std::string>(general, "chooseHomeTab", "Release");
|
||||
backgroundImageOpacity = toml::find_or<int>(general, "backgroundImageOpacity", 50);
|
||||
}
|
||||
|
||||
if (data.contains("Input")) {
|
||||
@ -783,6 +793,7 @@ void save(const std::filesystem::path& path) {
|
||||
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
|
||||
data["General"]["compatibilityEnabled"] = compatibilityData;
|
||||
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
|
||||
data["General"]["backgroundImageOpacity"] = backgroundImageOpacity;
|
||||
data["Input"]["cursorState"] = cursorState;
|
||||
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
|
||||
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
||||
@ -914,6 +925,7 @@ void setDefaultValues() {
|
||||
separateupdatefolder = false;
|
||||
compatibilityData = false;
|
||||
checkCompatibilityOnStartup = false;
|
||||
backgroundImageOpacity = 50;
|
||||
}
|
||||
|
||||
constexpr std::string_view GetDefaultKeyboardConfig() {
|
||||
|
@ -30,6 +30,7 @@ bool getEnableDiscordRPC();
|
||||
bool getSeparateUpdateEnabled();
|
||||
bool getCompatibilityEnabled();
|
||||
bool getCheckCompatibilityOnStartup();
|
||||
int getBackgroundImageOpacity();
|
||||
|
||||
std::string getLogFilter();
|
||||
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 setCompatibilityEnabled(bool use);
|
||||
void setCheckCompatibilityOnStartup(bool use);
|
||||
void setBackgroundImageOpacity(int opacity);
|
||||
|
||||
void setCursorState(s16 cursorState);
|
||||
void setCursorHideTimeout(int newcursorHideTimeout);
|
||||
|
@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "common/path_util.h"
|
||||
#include "game_grid_frame.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) {
|
||||
|
||||
int itemID = (row * this->columnCount()) + column;
|
||||
QWidget* item = this->cellWidget(row, column);
|
||||
if (item) {
|
||||
QString pic1Path;
|
||||
Common::FS::PathToQString(pic1Path, (*m_games_shared)[itemID].pic_path);
|
||||
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();
|
||||
if (!item) {
|
||||
// handle case where no item was clicked
|
||||
return;
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -167,26 +167,35 @@ void GameListFrame::SetListBackgroundImage(QTableWidgetItem* item) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString pic1Path;
|
||||
Common::FS::PathToQString(pic1Path, m_game_info->m_games[item->row()].pic_path);
|
||||
const auto blurredPic1Path = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
||||
m_game_info->m_games[item->row()].serial / "pic1.png";
|
||||
QString blurredPic1PathQt;
|
||||
Common::FS::PathToQString(blurredPic1PathQt, blurredPic1Path);
|
||||
const auto& game = m_game_info->m_games[item->row()];
|
||||
const int opacity = Config::getBackgroundImageOpacity();
|
||||
const auto cache_path = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
||||
game.serial / fmt::format("pic1_{}.png", opacity);
|
||||
|
||||
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_game_info->m_games[item->row()].serial;
|
||||
std::filesystem::create_directories(img_path);
|
||||
if (!backgroundImage.save(blurredPic1PathQt, "PNG")) {
|
||||
// qDebug() << "Error: Unable to save image.";
|
||||
// Fast path - try to load cached version first
|
||||
if (std::filesystem::exists(cache_path)) {
|
||||
backgroundImage = QImage(QString::fromStdString(cache_path.string()));
|
||||
if (!backgroundImage.isNull()) {
|
||||
RefreshListBackgroundImage();
|
||||
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");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
RefreshListBackgroundImage();
|
||||
}
|
||||
|
||||
|
@ -202,16 +202,17 @@ public:
|
||||
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
|
||||
QImage result = image.convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
|
||||
// Ensure opacity is between 0 and 1
|
||||
opacity = std::clamp(opacity, 0.0f, 1.0f);
|
||||
|
||||
|
||||
// Convert opacity to integer alpha value (0-255)
|
||||
int alpha = static_cast<int>(opacity * 255);
|
||||
|
||||
|
||||
// Process only the specified rectangle area
|
||||
for (int y = rect.top(); y <= rect.bottom(); ++y) {
|
||||
QRgb* line = reinterpret_cast<QRgb*>(result.scanLine(y));
|
||||
@ -223,7 +224,20 @@ public:
|
||||
line[x] = qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), newAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
[](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
|
||||
{
|
||||
@ -251,6 +255,7 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
||||
#ifdef ENABLE_UPDATER
|
||||
ui->updaterGroupBox->installEventFilter(this);
|
||||
#endif
|
||||
ui->GUIBackgroundImageGroupBox->installEventFilter(this);
|
||||
ui->GUIMusicGroupBox->installEventFilter(this);
|
||||
ui->disableTrophycheckBox->installEventFilter(this);
|
||||
ui->enableCompatibilityCheckBox->installEventFilter(this);
|
||||
@ -410,6 +415,7 @@ void SettingsDialog::LoadValuesFromConfig() {
|
||||
|
||||
ui->removeFolderButton->setEnabled(!ui->gameFoldersListWidget->selectedItems().isEmpty());
|
||||
ResetInstallFolders();
|
||||
ui->backgroundImageOpacitySlider->setValue(Config::getBackgroundImageOpacity());
|
||||
}
|
||||
|
||||
void SettingsDialog::InitializeEmulatorLanguages() {
|
||||
@ -504,6 +510,8 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
||||
} else if (elementName == "updaterGroupBox") {
|
||||
text = tr("updaterGroupBox");
|
||||
#endif
|
||||
} else if (elementName == "GUIBackgroundImageGroupBox") {
|
||||
text = tr("GUIBackgroundImageGroupBox");
|
||||
} else if (elementName == "GUIMusicGroupBox") {
|
||||
text = tr("GUIMusicGroupBox");
|
||||
} else if (elementName == "disableTrophycheckBox") {
|
||||
|
Loading…
Reference in New Issue
Block a user