mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-15 18:05:45 -04:00
PostProcessing: Refactor config to use separate sections
This commit is contained in:
@ -113,14 +113,9 @@ set(SRCS
|
||||
memorycardsettingswidget.h
|
||||
memoryviewwidget.cpp
|
||||
memoryviewwidget.h
|
||||
postprocessingchainconfigwidget.cpp
|
||||
postprocessingchainconfigwidget.h
|
||||
postprocessingchainconfigwidget.ui
|
||||
postprocessingsettingswidget.cpp
|
||||
postprocessingsettingswidget.h
|
||||
postprocessingsettingswidget.ui
|
||||
postprocessingshaderconfigwidget.cpp
|
||||
postprocessingshaderconfigwidget.h
|
||||
qthost.cpp
|
||||
qthost.h
|
||||
qtkeycodes.cpp
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "displaysettingswidget.h"
|
||||
#include "core/gpu.h"
|
||||
#include "core/settings.h"
|
||||
#include "postprocessingchainconfigwidget.h"
|
||||
#include "qtutils.h"
|
||||
#include "settingsdialog.h"
|
||||
#include "settingwidgetbinder.h"
|
||||
|
@ -41,8 +41,6 @@
|
||||
<ClCompile Include="mainwindow.cpp" />
|
||||
<ClCompile Include="memorycardsettingswidget.cpp" />
|
||||
<ClCompile Include="memorycardeditordialog.cpp" />
|
||||
<ClCompile Include="postprocessingchainconfigwidget.cpp" />
|
||||
<ClCompile Include="postprocessingshaderconfigwidget.cpp" />
|
||||
<ClCompile Include="postprocessingsettingswidget.cpp" />
|
||||
<ClCompile Include="qttranslations.cpp" />
|
||||
<ClCompile Include="qthost.cpp" />
|
||||
@ -93,8 +91,6 @@
|
||||
<QtMoc Include="gamesummarywidget.h" />
|
||||
<QtMoc Include="gdbconnection.h" />
|
||||
<QtMoc Include="gdbserver.h" />
|
||||
<QtMoc Include="postprocessingchainconfigwidget.h" />
|
||||
<QtMoc Include="postprocessingshaderconfigwidget.h" />
|
||||
<QtMoc Include="postprocessingsettingswidget.h" />
|
||||
<QtMoc Include="mainwindow.h" />
|
||||
<QtMoc Include="qthost.h" />
|
||||
@ -139,9 +135,6 @@
|
||||
<QtUi Include="advancedsettingswidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="postprocessingchainconfigwidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="postprocessingsettingswidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
@ -263,8 +256,6 @@
|
||||
<ClCompile Include="$(IntDir)moc_memorycardsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_memorycardeditordialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_memoryviewwidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_postprocessingchainconfigwidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_postprocessingshaderconfigwidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_postprocessingsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_qthost.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_qtprogresscallback.cpp" />
|
||||
|
@ -48,15 +48,11 @@
|
||||
<ClCompile Include="enhancementsettingswidget.cpp" />
|
||||
<ClCompile Include="displaysettingswidget.cpp" />
|
||||
<ClCompile Include="memorycardeditordialog.cpp" />
|
||||
<ClCompile Include="postprocessingchainconfigwidget.cpp" />
|
||||
<ClCompile Include="postprocessingshaderconfigwidget.cpp" />
|
||||
<ClCompile Include="postprocessingsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_biossettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_enhancementsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_displaysettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_memorycardeditordialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_postprocessingchainconfigwidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_postprocessingshaderconfigwidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_postprocessingsettingswidget.cpp" />
|
||||
<ClCompile Include="cheatmanagerdialog.cpp" />
|
||||
<ClCompile Include="cheatcodeeditordialog.cpp" />
|
||||
@ -136,8 +132,6 @@
|
||||
<QtMoc Include="enhancementsettingswidget.h" />
|
||||
<QtMoc Include="memorycardeditordialog.h" />
|
||||
<QtMoc Include="displaysettingswidget.h" />
|
||||
<QtMoc Include="postprocessingchainconfigwidget.h" />
|
||||
<QtMoc Include="postprocessingshaderconfigwidget.h" />
|
||||
<QtMoc Include="postprocessingsettingswidget.h" />
|
||||
<QtMoc Include="cheatmanagerdialog.h" />
|
||||
<QtMoc Include="cheatcodeeditordialog.h" />
|
||||
@ -171,7 +165,6 @@
|
||||
<QtUi Include="biossettingswidget.ui" />
|
||||
<QtUi Include="enhancementsettingswidget.ui" />
|
||||
<QtUi Include="displaysettingswidget.ui" />
|
||||
<QtUi Include="postprocessingchainconfigwidget.ui" />
|
||||
<QtUi Include="postprocessingsettingswidget.ui" />
|
||||
<QtUi Include="memorycardeditordialog.ui" />
|
||||
<QtUi Include="cheatmanagerdialog.ui" />
|
||||
@ -264,4 +257,4 @@
|
||||
<Filter>translations</Filter>
|
||||
</QtTs>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -1,219 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#include "postprocessingchainconfigwidget.h"
|
||||
#include "postprocessingshaderconfigwidget.h"
|
||||
#include "qthost.h"
|
||||
|
||||
#include "util/postprocessing_chain.h"
|
||||
|
||||
#include <QtGui/QCursor>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
PostProcessingChainConfigWidget::PostProcessingChainConfigWidget(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
connectUi();
|
||||
updateButtonStates(std::nullopt);
|
||||
}
|
||||
|
||||
PostProcessingChainConfigWidget::~PostProcessingChainConfigWidget() = default;
|
||||
|
||||
void PostProcessingChainConfigWidget::connectUi()
|
||||
{
|
||||
connect(m_ui.add, &QToolButton::clicked, this, &PostProcessingChainConfigWidget::onAddButtonClicked);
|
||||
connect(m_ui.remove, &QToolButton::clicked, this, &PostProcessingChainConfigWidget::onRemoveButtonClicked);
|
||||
connect(m_ui.clear, &QToolButton::clicked, this, &PostProcessingChainConfigWidget::onClearButtonClicked);
|
||||
connect(m_ui.moveUp, &QToolButton::clicked, this, &PostProcessingChainConfigWidget::onMoveUpButtonClicked);
|
||||
connect(m_ui.moveDown, &QToolButton::clicked, this, &PostProcessingChainConfigWidget::onMoveDownButtonClicked);
|
||||
// connect(m_ui.reload, &QToolButton::clicked, this, &PostProcessingChainConfigWidget::onReloadButtonClicked);
|
||||
connect(m_ui.shaderSettings, &QToolButton::clicked, this,
|
||||
&PostProcessingChainConfigWidget::onShaderConfigButtonClicked);
|
||||
connect(m_ui.shaders, &QListWidget::itemSelectionChanged, this,
|
||||
&PostProcessingChainConfigWidget::onSelectedShaderChanged);
|
||||
|
||||
// m_ui.loadPreset->setEnabled(false);
|
||||
// m_ui.savePreset->setEnabled(false);
|
||||
}
|
||||
|
||||
bool PostProcessingChainConfigWidget::setConfigString(const std::string_view& config_string)
|
||||
{
|
||||
if (!m_chain.CreateFromString(config_string))
|
||||
return false;
|
||||
|
||||
updateList();
|
||||
return true;
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::setOptionsButtonVisible(bool visible)
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
m_ui.shaderSettings->setVisible(true);
|
||||
m_ui.horizontalLayout->addWidget(m_ui.shaderSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.shaderSettings->setVisible(false);
|
||||
m_ui.horizontalLayout->removeWidget(m_ui.shaderSettings);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<u32> PostProcessingChainConfigWidget::getSelectedIndex() const
|
||||
{
|
||||
QList<QListWidgetItem*> selected_items = m_ui.shaders->selectedItems();
|
||||
return selected_items.empty() ? std::nullopt :
|
||||
std::optional<u32>(selected_items.first()->data(Qt::UserRole).toUInt());
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::updateList()
|
||||
{
|
||||
m_ui.shaders->clear();
|
||||
|
||||
for (u32 i = 0; i < m_chain.GetStageCount(); i++)
|
||||
{
|
||||
const PostProcessingShader* shader = m_chain.GetShaderStage(i);
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(shader->GetName()), m_ui.shaders);
|
||||
item->setData(Qt::UserRole, QVariant(i));
|
||||
}
|
||||
|
||||
updateButtonStates(std::nullopt);
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::configChanged()
|
||||
{
|
||||
if (m_chain.IsEmpty())
|
||||
chainConfigStringChanged(std::string());
|
||||
else
|
||||
chainConfigStringChanged(m_chain.GetConfigString());
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::updateButtonStates(std::optional<u32> index)
|
||||
{
|
||||
m_ui.remove->setEnabled(index.has_value());
|
||||
m_ui.clear->setEnabled(!m_chain.IsEmpty());
|
||||
// m_ui.reload->setEnabled(!m_chain.IsEmpty());
|
||||
m_ui.shaderSettings->setEnabled(index.has_value() && (index.value() < m_chain.GetStageCount()) &&
|
||||
m_chain.GetShaderStage(index.value())->HasOptions());
|
||||
|
||||
if (index.has_value())
|
||||
{
|
||||
m_ui.moveUp->setEnabled(index.value() > 0);
|
||||
m_ui.moveDown->setEnabled(index.value() < (m_chain.GetStageCount() - 1u));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.moveUp->setEnabled(false);
|
||||
m_ui.moveDown->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::onAddButtonClicked()
|
||||
{
|
||||
QMenu menu;
|
||||
|
||||
const std::vector<std::string> shaders(PostProcessingChain::GetAvailableShaderNames());
|
||||
if (shaders.empty())
|
||||
{
|
||||
menu.addAction(tr("No Shaders Available"))->setEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const std::string& shader : shaders)
|
||||
{
|
||||
QAction* action = menu.addAction(QString::fromStdString(shader));
|
||||
connect(action, &QAction::triggered, [this, &shader]() {
|
||||
chainAboutToChange();
|
||||
|
||||
if (!m_chain.AddStage(shader))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to add shader. The log may contain more information."));
|
||||
return;
|
||||
}
|
||||
|
||||
updateList();
|
||||
configChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::onRemoveButtonClicked()
|
||||
{
|
||||
QList<QListWidgetItem*> selected_items = m_ui.shaders->selectedItems();
|
||||
if (selected_items.empty())
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = selected_items.first();
|
||||
u32 index = item->data(Qt::UserRole).toUInt();
|
||||
if (index < m_chain.GetStageCount())
|
||||
{
|
||||
chainAboutToChange();
|
||||
m_chain.RemoveStage(index);
|
||||
updateList();
|
||||
configChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::onClearButtonClicked()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Question"), tr("Are you sure you want to clear all shader stages?"),
|
||||
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
|
||||
{
|
||||
chainAboutToChange();
|
||||
m_chain.ClearStages();
|
||||
updateList();
|
||||
configChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::onMoveUpButtonClicked()
|
||||
{
|
||||
std::optional<u32> index = getSelectedIndex();
|
||||
if (index.has_value())
|
||||
{
|
||||
chainAboutToChange();
|
||||
m_chain.MoveStageUp(index.value());
|
||||
updateList();
|
||||
configChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::onMoveDownButtonClicked()
|
||||
{
|
||||
std::optional<u32> index = getSelectedIndex();
|
||||
if (index.has_value())
|
||||
{
|
||||
chainAboutToChange();
|
||||
m_chain.MoveStageDown(index.value());
|
||||
updateList();
|
||||
configChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::onShaderConfigButtonClicked()
|
||||
{
|
||||
std::optional<u32> index = getSelectedIndex();
|
||||
if (index.has_value() && index.value() < m_chain.GetStageCount())
|
||||
{
|
||||
PostProcessingShaderConfigDialog shader_config(this, m_chain.GetShaderStage(index.value()));
|
||||
connect(&shader_config, &PostProcessingShaderConfigDialog::configChanged, [this]() { configChanged(); });
|
||||
shader_config.exec();
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::onReloadButtonClicked()
|
||||
{
|
||||
g_emu_thread->reloadPostProcessingShaders();
|
||||
}
|
||||
|
||||
void PostProcessingChainConfigWidget::onSelectedShaderChanged()
|
||||
{
|
||||
std::optional<u32> index = getSelectedIndex();
|
||||
selectedShaderChanged(index.has_value() ? static_cast<s32>(index.value()) : -1);
|
||||
updateButtonStates(index);
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
#include "ui_postprocessingchainconfigwidget.h"
|
||||
|
||||
#include "util/postprocessing_chain.h"
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace PlatformMisc {
|
||||
class PostProcessingChain;
|
||||
}
|
||||
|
||||
class PostProcessingChainConfigWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PostProcessingChainConfigWidget(QWidget* parent);
|
||||
~PostProcessingChainConfigWidget();
|
||||
|
||||
ALWAYS_INLINE PostProcessingChain& getChain() { return m_chain; }
|
||||
|
||||
bool setConfigString(const std::string_view& config_string);
|
||||
void setOptionsButtonVisible(bool visible);
|
||||
|
||||
Q_SIGNALS:
|
||||
void selectedShaderChanged(qint32 index);
|
||||
void chainAboutToChange();
|
||||
void chainConfigStringChanged(const std::string& new_config_string);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onAddButtonClicked();
|
||||
void onRemoveButtonClicked();
|
||||
void onClearButtonClicked();
|
||||
void onMoveUpButtonClicked();
|
||||
void onMoveDownButtonClicked();
|
||||
void onShaderConfigButtonClicked();
|
||||
void onReloadButtonClicked();
|
||||
void onSelectedShaderChanged();
|
||||
|
||||
private:
|
||||
void connectUi();
|
||||
std::optional<u32> getSelectedIndex() const;
|
||||
void updateList();
|
||||
void configChanged();
|
||||
void updateButtonStates(std::optional<u32> index);
|
||||
|
||||
Ui::PostProcessingChainConfigWidget m_ui;
|
||||
|
||||
PostProcessingChain m_chain;
|
||||
};
|
@ -1,163 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PostProcessingChainConfigWidget</class>
|
||||
<widget class="QWidget" name="PostProcessingChainConfigWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>721</width>
|
||||
<height>210</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QListWidget" name="shaders">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QToolButton" name="add">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="PostProcessingAdd"/>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="remove">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="PostProcessingRemove"/>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="clear">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="Clear"/>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="moveUp">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Move Up</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="MoveUp"/>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="moveDown">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Move Down</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="MoveDown"/>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="shaderSettings">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Options...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="Options"/>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="resources/resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
@ -1,10 +1,20 @@
|
||||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#include "postprocessingsettingswidget.h"
|
||||
#include "qthost.h"
|
||||
#include "settingwidgetbinder.h"
|
||||
|
||||
#include "util/postprocessing.h"
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
#include <QtWidgets/QCheckBox>
|
||||
#include <QtWidgets/QDialogButtonBox>
|
||||
#include <QtWidgets/QGridLayout>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QSlider>
|
||||
|
||||
PostProcessingSettingsWidget::PostProcessingSettingsWidget(SettingsDialog* dialog, QWidget* parent)
|
||||
: QWidget(parent), m_dialog(dialog)
|
||||
@ -12,53 +22,101 @@ PostProcessingSettingsWidget::PostProcessingSettingsWidget(SettingsDialog* dialo
|
||||
SettingsInterface* sif = dialog->getSettingsInterface();
|
||||
|
||||
m_ui.setupUi(this);
|
||||
m_ui.widget->setOptionsButtonVisible(false);
|
||||
m_ui.reload->setEnabled(false);
|
||||
updateShaderConfigPanel(-1);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enablePostProcessing, "PostProcessing", "Enabled", false);
|
||||
|
||||
updateList();
|
||||
updateButtonsAndConfigPane(std::nullopt);
|
||||
connectUi();
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enablePostProcessing, "Display", "PostProcessing", false);
|
||||
|
||||
std::string post_chain = m_dialog->getStringValue("Display", "PostProcessChain", "").value_or(std::string());
|
||||
if (!post_chain.empty())
|
||||
{
|
||||
if (!m_ui.widget->setConfigString(post_chain))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("The current post-processing chain is invalid, it has been reset."));
|
||||
m_dialog->removeSettingValue("Display", "PostProcessChain");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.reload->setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PostProcessingSettingsWidget::~PostProcessingSettingsWidget() = default;
|
||||
|
||||
SettingsInterface& PostProcessingSettingsWidget::getSettingsInterfaceToUpdate()
|
||||
{
|
||||
return m_dialog->isPerGameSettings() ? *m_dialog->getSettingsInterface() : *Host::Internal::GetBaseSettingsLayer();
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::commitSettingsUpdate()
|
||||
{
|
||||
if (m_dialog->isPerGameSettings())
|
||||
m_dialog->getSettingsInterface()->Save();
|
||||
else
|
||||
Host::CommitBaseSettingChanges();
|
||||
|
||||
g_emu_thread->updatePostProcessingSettings();
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::connectUi()
|
||||
{
|
||||
connect(m_ui.reload, &QPushButton::clicked, this, &PostProcessingSettingsWidget::onReloadClicked);
|
||||
connect(m_ui.widget, &PostProcessingChainConfigWidget::chainAboutToChange, this,
|
||||
&PostProcessingSettingsWidget::onChainAboutToChange);
|
||||
connect(m_ui.widget, &PostProcessingChainConfigWidget::selectedShaderChanged, this,
|
||||
&PostProcessingSettingsWidget::onChainSelectedShaderChanged);
|
||||
connect(m_ui.widget, &PostProcessingChainConfigWidget::chainConfigStringChanged, this,
|
||||
&PostProcessingSettingsWidget::onConfigChanged);
|
||||
connect(m_ui.reload, &QPushButton::clicked, this, &PostProcessingSettingsWidget::onReloadButtonClicked);
|
||||
connect(m_ui.add, &QToolButton::clicked, this, &PostProcessingSettingsWidget::onAddButtonClicked);
|
||||
connect(m_ui.remove, &QToolButton::clicked, this, &PostProcessingSettingsWidget::onRemoveButtonClicked);
|
||||
connect(m_ui.clear, &QToolButton::clicked, this, &PostProcessingSettingsWidget::onClearButtonClicked);
|
||||
connect(m_ui.moveUp, &QToolButton::clicked, this, &PostProcessingSettingsWidget::onMoveUpButtonClicked);
|
||||
connect(m_ui.moveDown, &QToolButton::clicked, this, &PostProcessingSettingsWidget::onMoveDownButtonClicked);
|
||||
connect(m_ui.stages, &QListWidget::itemSelectionChanged, this,
|
||||
&PostProcessingSettingsWidget::onSelectedShaderChanged);
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::onChainAboutToChange()
|
||||
std::optional<u32> PostProcessingSettingsWidget::getSelectedIndex() const
|
||||
{
|
||||
updateShaderConfigPanel(-1);
|
||||
QList<QListWidgetItem*> selected_items = m_ui.stages->selectedItems();
|
||||
return selected_items.empty() ? std::nullopt :
|
||||
std::optional<u32>(selected_items.first()->data(Qt::UserRole).toUInt());
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::onChainSelectedShaderChanged(qint32 index)
|
||||
void PostProcessingSettingsWidget::selectIndex(s32 index)
|
||||
{
|
||||
updateShaderConfigPanel(index);
|
||||
if (index < 0 || index >= m_ui.stages->count())
|
||||
return;
|
||||
|
||||
QSignalBlocker sb(m_ui.stages);
|
||||
m_ui.stages->setCurrentItem(m_ui.stages->item(index));
|
||||
updateButtonsAndConfigPane(index);
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::updateShaderConfigPanel(s32 index)
|
||||
void PostProcessingSettingsWidget::updateList()
|
||||
{
|
||||
const auto lock = Host::GetSettingsLock();
|
||||
const SettingsInterface& si = getSettingsInterfaceToUpdate();
|
||||
|
||||
updateList(si);
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::updateList(const SettingsInterface& si)
|
||||
{
|
||||
m_ui.stages->clear();
|
||||
|
||||
const u32 stage_count = PostProcessing::Config::GetStageCount(si);
|
||||
|
||||
for (u32 i = 0; i < stage_count; i++)
|
||||
{
|
||||
const std::string stage_name = PostProcessing::Config::GetStageShaderName(si, i);
|
||||
QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(stage_name), m_ui.stages);
|
||||
item->setData(Qt::UserRole, QVariant(i));
|
||||
}
|
||||
|
||||
m_ui.clear->setEnabled(stage_count > 0);
|
||||
m_ui.reload->setEnabled(stage_count > 0);
|
||||
updateButtonsAndConfigPane(std::nullopt);
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::updateButtonsAndConfigPane(std::optional<u32> index)
|
||||
{
|
||||
m_ui.remove->setEnabled(index.has_value());
|
||||
|
||||
if (index.has_value())
|
||||
{
|
||||
m_ui.moveUp->setEnabled(index.value() > 0);
|
||||
m_ui.moveDown->setEnabled(index.value() < static_cast<u32>(m_ui.stages->count() - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.moveUp->setEnabled(false);
|
||||
m_ui.moveDown->setEnabled(false);
|
||||
}
|
||||
|
||||
m_ui.scrollArea->setWidget(nullptr);
|
||||
m_ui.scrollArea->setVisible(false);
|
||||
|
||||
@ -68,35 +126,282 @@ void PostProcessingSettingsWidget::updateShaderConfigPanel(s32 index)
|
||||
m_shader_config = nullptr;
|
||||
}
|
||||
|
||||
if (index < 0)
|
||||
if (!index.has_value())
|
||||
return;
|
||||
|
||||
PostProcessingShader* shader = m_ui.widget->getChain().GetShaderStage(static_cast<u32>(index));
|
||||
if (!shader->HasOptions())
|
||||
const auto lock = Host::GetSettingsLock();
|
||||
const SettingsInterface& si = getSettingsInterfaceToUpdate();
|
||||
std::vector<PostProcessing::ShaderOption> options = PostProcessing::Config::GetStageOptions(si, index.value());
|
||||
if (options.empty())
|
||||
return;
|
||||
|
||||
m_shader_config = new PostProcessingShaderConfigWidget(m_ui.scrollArea, shader);
|
||||
connect(m_shader_config, &PostProcessingShaderConfigWidget::configChanged,
|
||||
[this]() { onConfigChanged(m_ui.widget->getChain().GetConfigString()); });
|
||||
m_shader_config = new PostProcessingShaderConfigWidget(m_ui.scrollArea, this, index.value(), std::move(options));
|
||||
m_ui.scrollArea->setWidget(m_shader_config);
|
||||
m_ui.scrollArea->setVisible(true);
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::onConfigChanged(const std::string& new_config)
|
||||
void PostProcessingSettingsWidget::onAddButtonClicked()
|
||||
{
|
||||
if (new_config.empty())
|
||||
QMenu menu;
|
||||
|
||||
const std::vector<std::pair<std::string, std::string>> shaders = PostProcessing::GetAvailableShaderNames();
|
||||
if (shaders.empty())
|
||||
{
|
||||
m_dialog->removeSettingValue("Display", "PostProcessChain");
|
||||
m_ui.reload->setEnabled(false);
|
||||
menu.addAction(tr("No Shaders Available"))->setEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dialog->setStringSettingValue("Display", "PostProcessChain", new_config.c_str());
|
||||
m_ui.reload->setEnabled(true);
|
||||
for (auto& [display_name, name] : shaders)
|
||||
{
|
||||
QAction* action = menu.addAction(QString::fromStdString(display_name));
|
||||
connect(action, &QAction::triggered, [this, shader = std::move(name)]() {
|
||||
auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface& si = getSettingsInterfaceToUpdate();
|
||||
|
||||
Error error;
|
||||
if (!PostProcessing::Config::AddStage(si, shader, &error))
|
||||
{
|
||||
lock.unlock();
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Failed to add shader: %1").arg(QString::fromStdString(error.GetDescription())));
|
||||
return;
|
||||
}
|
||||
|
||||
updateList(si);
|
||||
lock.unlock();
|
||||
commitSettingsUpdate();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::onRemoveButtonClicked()
|
||||
{
|
||||
QList<QListWidgetItem*> selected_items = m_ui.stages->selectedItems();
|
||||
if (selected_items.empty())
|
||||
return;
|
||||
|
||||
auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface& si = getSettingsInterfaceToUpdate();
|
||||
|
||||
QListWidgetItem* item = selected_items.first();
|
||||
u32 index = item->data(Qt::UserRole).toUInt();
|
||||
if (index < PostProcessing::Config::GetStageCount(si))
|
||||
{
|
||||
PostProcessing::Config::RemoveStage(si, index);
|
||||
updateList(si);
|
||||
lock.unlock();
|
||||
commitSettingsUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::onReloadClicked()
|
||||
void PostProcessingSettingsWidget::onClearButtonClicked()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Question"), tr("Are you sure you want to clear all shader stages?"),
|
||||
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface& si = getSettingsInterfaceToUpdate();
|
||||
PostProcessing::Config::ClearStages(si);
|
||||
updateList(si);
|
||||
lock.unlock();
|
||||
commitSettingsUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::onMoveUpButtonClicked()
|
||||
{
|
||||
std::optional<u32> index = getSelectedIndex();
|
||||
if (index.has_value() && index.value() > 0)
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface& si = getSettingsInterfaceToUpdate();
|
||||
PostProcessing::Config::MoveStageUp(si, index.value());
|
||||
updateList(si);
|
||||
lock.unlock();
|
||||
selectIndex(index.value() - 1);
|
||||
commitSettingsUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::onMoveDownButtonClicked()
|
||||
{
|
||||
std::optional<u32> index = getSelectedIndex();
|
||||
if (index.has_value() || index.value() < (static_cast<u32>(m_ui.stages->count() - 1)))
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface& si = getSettingsInterfaceToUpdate();
|
||||
PostProcessing::Config::MoveStageDown(si, index.value());
|
||||
updateList(si);
|
||||
lock.unlock();
|
||||
selectIndex(index.value() + 1);
|
||||
commitSettingsUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::onReloadButtonClicked()
|
||||
{
|
||||
g_emu_thread->reloadPostProcessingShaders();
|
||||
}
|
||||
|
||||
void PostProcessingSettingsWidget::onSelectedShaderChanged()
|
||||
{
|
||||
std::optional<u32> index = getSelectedIndex();
|
||||
updateButtonsAndConfigPane(index);
|
||||
}
|
||||
|
||||
PostProcessingShaderConfigWidget::PostProcessingShaderConfigWidget(QWidget* parent,
|
||||
PostProcessingSettingsWidget* widget,
|
||||
u32 stage_index,
|
||||
std::vector<PostProcessing::ShaderOption> options)
|
||||
: QWidget(parent), m_widget(widget), m_stage_index(stage_index), m_options(std::move(options))
|
||||
{
|
||||
m_layout = new QGridLayout(this);
|
||||
|
||||
createUi();
|
||||
}
|
||||
|
||||
PostProcessingShaderConfigWidget::~PostProcessingShaderConfigWidget() = default;
|
||||
|
||||
void PostProcessingShaderConfigWidget::updateConfigForOption(const PostProcessing::ShaderOption& option)
|
||||
{
|
||||
const auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface& si = m_widget->getSettingsInterfaceToUpdate();
|
||||
PostProcessing::Config::SetStageOption(si, m_stage_index, option);
|
||||
m_widget->commitSettingsUpdate();
|
||||
}
|
||||
|
||||
void PostProcessingShaderConfigWidget::onResetDefaultsClicked()
|
||||
{
|
||||
{
|
||||
const auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface& si = m_widget->getSettingsInterfaceToUpdate();
|
||||
for (PostProcessing::ShaderOption& option : m_options)
|
||||
{
|
||||
if (std::memcmp(option.value.data(), option.default_value.data(), sizeof(option.value)) == 0)
|
||||
continue;
|
||||
|
||||
option.value = option.default_value;
|
||||
PostProcessing::Config::UnsetStageOption(si, m_stage_index, option);
|
||||
}
|
||||
m_widget->commitSettingsUpdate();
|
||||
}
|
||||
|
||||
// Toss and recreate UI.
|
||||
for (auto it = m_widgets.rbegin(); it != m_widgets.rend(); ++it)
|
||||
{
|
||||
m_layout->removeWidget(*it);
|
||||
delete *it;
|
||||
}
|
||||
m_widgets.clear();
|
||||
createUi();
|
||||
}
|
||||
|
||||
void PostProcessingShaderConfigWidget::createUi()
|
||||
{
|
||||
u32 row = 0;
|
||||
|
||||
for (PostProcessing::ShaderOption& option : m_options)
|
||||
{
|
||||
if (option.ui_name.empty())
|
||||
continue;
|
||||
|
||||
if (option.type == PostProcessing::ShaderOption::Type::Bool)
|
||||
{
|
||||
QCheckBox* checkbox = new QCheckBox(QString::fromStdString(option.ui_name), this);
|
||||
checkbox->setChecked(option.value[0].int_value != 0);
|
||||
connect(checkbox, &QCheckBox::stateChanged, [this, &option](int state) {
|
||||
option.value[0].int_value = (state == Qt::Checked) ? 1 : 0;
|
||||
updateConfigForOption(option);
|
||||
});
|
||||
m_layout->addWidget(checkbox, row, 0, 1, 3, Qt::AlignLeft);
|
||||
m_widgets.push_back(checkbox);
|
||||
row++;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < option.vector_size; i++)
|
||||
{
|
||||
QString label;
|
||||
if (option.vector_size <= 1)
|
||||
{
|
||||
label = QString::fromStdString(option.ui_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
static constexpr std::array<const char*, PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS + 1> suffixes = {
|
||||
{QT_TR_NOOP("Red"), QT_TR_NOOP("Green"), QT_TR_NOOP("Blue"), QT_TR_NOOP("Alpha")}};
|
||||
label = tr("%1 (%2)").arg(QString::fromStdString(option.ui_name)).arg(tr(suffixes[i]));
|
||||
}
|
||||
|
||||
QWidget* label_w = new QLabel(label, this);
|
||||
m_layout->addWidget(label_w, row, 0, 1, 1, Qt::AlignLeft);
|
||||
m_widgets.push_back(label_w);
|
||||
|
||||
QSlider* slider = new QSlider(Qt::Horizontal, this);
|
||||
m_layout->addWidget(slider, row, 1, 1, 1, Qt::AlignLeft);
|
||||
m_widgets.push_back(slider);
|
||||
|
||||
QLabel* slider_label = new QLabel(this);
|
||||
m_layout->addWidget(slider_label, row, 2, 1, 1, Qt::AlignLeft);
|
||||
m_widgets.push_back(slider_label);
|
||||
|
||||
if (option.type == PostProcessing::ShaderOption::Type::Int)
|
||||
{
|
||||
slider_label->setText(QString::number(option.value[i].int_value));
|
||||
|
||||
const int range = option.max_value[i].int_value - option.min_value[i].int_value;
|
||||
const int step_value =
|
||||
(option.step_value[i].int_value != 0) ? option.step_value[i].int_value : ((range + 99) / 100);
|
||||
const int num_steps = range / step_value;
|
||||
slider->setMinimum(0);
|
||||
slider->setMaximum(num_steps);
|
||||
slider->setSingleStep(1);
|
||||
slider->setTickInterval(step_value);
|
||||
slider->setValue((option.value[i].int_value - option.min_value[i].int_value) / step_value);
|
||||
connect(slider, &QSlider::valueChanged, [this, &option, i, slider_label](int value) {
|
||||
const int new_value = std::clamp(option.min_value[i].int_value + (value * option.step_value[i].int_value),
|
||||
option.min_value[i].int_value, option.max_value[i].int_value);
|
||||
option.value[i].int_value = new_value;
|
||||
slider_label->setText(QString::number(new_value));
|
||||
updateConfigForOption(option);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
slider_label->setText(QString::number(option.value[i].float_value));
|
||||
|
||||
const float range = option.max_value[i].float_value - option.min_value[i].float_value;
|
||||
const float step_value =
|
||||
(option.step_value[i].float_value != 0) ? option.step_value[i].float_value : ((range + 99.0f) / 100.0f);
|
||||
const float num_steps = std::ceil(range / step_value);
|
||||
slider->setMinimum(0);
|
||||
slider->setMaximum(num_steps);
|
||||
slider->setSingleStep(1);
|
||||
slider->setTickInterval(step_value);
|
||||
slider->setValue(
|
||||
static_cast<int>((option.value[i].float_value - option.min_value[i].float_value) / step_value));
|
||||
connect(slider, &QSlider::valueChanged, [this, &option, i, slider_label](int value) {
|
||||
const float new_value = std::clamp(option.min_value[i].float_value +
|
||||
(static_cast<float>(value) * option.step_value[i].float_value),
|
||||
option.min_value[i].float_value, option.max_value[i].float_value);
|
||||
option.value[i].float_value = new_value;
|
||||
slider_label->setText(QString::number(new_value));
|
||||
updateConfigForOption(option);
|
||||
});
|
||||
}
|
||||
|
||||
row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::RestoreDefaults, this);
|
||||
connect(button_box, &QDialogButtonBox::clicked, this, &PostProcessingShaderConfigWidget::onResetDefaultsClicked);
|
||||
m_layout->addWidget(button_box, row, 0, 1, -1);
|
||||
|
||||
row++;
|
||||
m_layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding), row, 0, 1, 3);
|
||||
}
|
||||
|
@ -2,34 +2,74 @@
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
#include "postprocessingchainconfigwidget.h"
|
||||
#include "postprocessingshaderconfigwidget.h"
|
||||
|
||||
#include "ui_postprocessingsettingswidget.h"
|
||||
|
||||
#include "util/postprocessing.h"
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
class SettingsDialog;
|
||||
class PostProcessingShaderConfigWidget;
|
||||
|
||||
class PostProcessingSettingsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend PostProcessingShaderConfigWidget;
|
||||
|
||||
public:
|
||||
PostProcessingSettingsWidget(SettingsDialog* dialog, QWidget* parent);
|
||||
~PostProcessingSettingsWidget();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onChainAboutToChange();
|
||||
void onChainSelectedShaderChanged(qint32 index);
|
||||
void onConfigChanged(const std::string& new_config);
|
||||
void onReloadClicked();
|
||||
void onAddButtonClicked();
|
||||
void onRemoveButtonClicked();
|
||||
void onClearButtonClicked();
|
||||
void onMoveUpButtonClicked();
|
||||
void onMoveDownButtonClicked();
|
||||
void onReloadButtonClicked();
|
||||
void onSelectedShaderChanged();
|
||||
|
||||
private:
|
||||
SettingsInterface& getSettingsInterfaceToUpdate();
|
||||
void commitSettingsUpdate();
|
||||
|
||||
void connectUi();
|
||||
void updateShaderConfigPanel(s32 index);
|
||||
|
||||
void updateButtonsAndConfigPane(std::optional<u32> index);
|
||||
std::optional<u32> getSelectedIndex() const;
|
||||
void selectIndex(s32 index);
|
||||
void updateList(const SettingsInterface& si);
|
||||
void updateList();
|
||||
|
||||
SettingsDialog* m_dialog;
|
||||
|
||||
Ui::PostProcessingSettingsWidget m_ui;
|
||||
|
||||
PostProcessingShaderConfigWidget* m_shader_config = nullptr;
|
||||
};
|
||||
|
||||
class PostProcessingShaderConfigWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PostProcessingShaderConfigWidget(QWidget* parent, PostProcessingSettingsWidget* widget, u32 stage_index,
|
||||
std::vector<PostProcessing::ShaderOption> options);
|
||||
~PostProcessingShaderConfigWidget();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onResetDefaultsClicked();
|
||||
|
||||
protected:
|
||||
void createUi();
|
||||
void updateConfigForOption(const PostProcessing::ShaderOption& option);
|
||||
|
||||
QGridLayout* m_layout;
|
||||
|
||||
PostProcessingSettingsWidget* m_widget;
|
||||
std::vector<QWidget*> m_widgets;
|
||||
|
||||
u32 m_stage_index;
|
||||
std::vector<PostProcessing::ShaderOption> m_options;
|
||||
};
|
||||
|
@ -67,20 +67,125 @@
|
||||
<string>Post Processing Chain</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="PostProcessingChainConfigWidget" name="widget" native="true"/>
|
||||
<widget class="QListWidget" name="stages">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QToolButton" name="add">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="PostProcessingAdd">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="remove">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="PostProcessingRemove">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="clear">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="Clear">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="moveUp">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Move Up</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="MoveUp">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="moveDown">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Move Down</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="MoveDown">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@ -108,7 +213,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>679</width>
|
||||
<height>438</height>
|
||||
<height>238</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
@ -129,14 +234,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>PostProcessingChainConfigWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>duckstation-qt/postprocessingchainconfigwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="resources/resources.qrc"/>
|
||||
</resources>
|
||||
|
@ -1,175 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#include "postprocessingshaderconfigwidget.h"
|
||||
#include <QtWidgets/QCheckBox>
|
||||
#include <QtWidgets/QDialogButtonBox>
|
||||
#include <QtWidgets/QGridLayout>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QSlider>
|
||||
|
||||
PostProcessingShaderConfigWidget::PostProcessingShaderConfigWidget(QWidget* parent,
|
||||
PostProcessingShader* shader)
|
||||
: QWidget(parent), m_shader(shader)
|
||||
{
|
||||
createUi();
|
||||
}
|
||||
|
||||
PostProcessingShaderConfigWidget::~PostProcessingShaderConfigWidget() = default;
|
||||
|
||||
void PostProcessingShaderConfigWidget::createUi()
|
||||
{
|
||||
m_layout = new QGridLayout(this);
|
||||
u32 row = 0;
|
||||
|
||||
for (PostProcessingShader::Option& option : m_shader->GetOptions())
|
||||
{
|
||||
if (option.type == PostProcessingShader::Option::Type::Bool)
|
||||
{
|
||||
QCheckBox* checkbox = new QCheckBox(QString::fromStdString(option.ui_name), this);
|
||||
checkbox->setChecked(option.value[0].int_value != 0);
|
||||
connect(checkbox, &QCheckBox::stateChanged, [this, &option](int state) {
|
||||
option.value[0].int_value = (state == Qt::Checked) ? 1 : 0;
|
||||
configChanged();
|
||||
});
|
||||
connect(this, &PostProcessingShaderConfigWidget::resettingtoDefaults, [&option, checkbox]() {
|
||||
QSignalBlocker sb(checkbox);
|
||||
checkbox->setChecked(option.default_value[0].int_value != 0);
|
||||
option.value = option.default_value;
|
||||
});
|
||||
m_layout->addWidget(checkbox, row, 0, 1, 3, Qt::AlignLeft);
|
||||
row++;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < option.vector_size; i++)
|
||||
{
|
||||
QString label;
|
||||
if (option.vector_size <= 1)
|
||||
{
|
||||
label = QString::fromStdString(option.ui_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
static constexpr std::array<const char*, PostProcessingShader::Option::MAX_VECTOR_COMPONENTS + 1> suffixes = {
|
||||
{QT_TR_NOOP("Red"), QT_TR_NOOP("Green"), QT_TR_NOOP("Blue"), QT_TR_NOOP("Alpha")}};
|
||||
label = tr("%1 (%2)").arg(QString::fromStdString(option.ui_name)).arg(tr(suffixes[i]));
|
||||
}
|
||||
|
||||
m_layout->addWidget(new QLabel(label, this), row, 0, 1, 1, Qt::AlignLeft);
|
||||
|
||||
QSlider* slider = new QSlider(Qt::Horizontal, this);
|
||||
m_layout->addWidget(slider, row, 1, 1, 1, Qt::AlignLeft);
|
||||
|
||||
QLabel* slider_label = new QLabel(this);
|
||||
m_layout->addWidget(slider_label, row, 2, 1, 1, Qt::AlignLeft);
|
||||
|
||||
if (option.type == PostProcessingShader::Option::Type::Int)
|
||||
{
|
||||
slider_label->setText(QString::number(option.value[i].int_value));
|
||||
|
||||
const int range = std::max(option.max_value[i].int_value - option.min_value[i].int_value, 1);
|
||||
const int step_value =
|
||||
(option.step_value[i].int_value != 0) ? option.step_value[i].int_value : ((range + 99) / 100);
|
||||
const int num_steps = range / step_value;
|
||||
slider->setMinimum(0);
|
||||
slider->setMaximum(num_steps);
|
||||
slider->setSingleStep(1);
|
||||
slider->setTickInterval(step_value);
|
||||
slider->setValue((option.value[i].int_value - option.min_value[i].int_value) / step_value);
|
||||
connect(slider, &QSlider::valueChanged, [this, &option, i, slider_label](int value) {
|
||||
const int new_value = std::clamp(option.min_value[i].int_value + (value * option.step_value[i].int_value),
|
||||
option.min_value[i].int_value, option.max_value[i].int_value);
|
||||
option.value[i].int_value = new_value;
|
||||
slider_label->setText(QString::number(new_value));
|
||||
configChanged();
|
||||
});
|
||||
connect(this, &PostProcessingShaderConfigWidget::resettingtoDefaults,
|
||||
[&option, i, slider, slider_label, step_value]() {
|
||||
QSignalBlocker sb(slider);
|
||||
slider->setValue((option.default_value[i].int_value - option.min_value[i].int_value) / step_value);
|
||||
slider_label->setText(QString::number(option.default_value[i].int_value));
|
||||
option.value = option.default_value;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
slider_label->setText(QString::number(option.value[i].float_value));
|
||||
|
||||
const float range = std::max(option.max_value[i].float_value - option.min_value[i].float_value, 1.0f);
|
||||
const float step_value =
|
||||
(option.step_value[i].float_value != 0) ? option.step_value[i].float_value : ((range + 99.0f) / 100.0f);
|
||||
const float num_steps = range / step_value;
|
||||
slider->setMinimum(0);
|
||||
slider->setMaximum(num_steps);
|
||||
slider->setSingleStep(1);
|
||||
slider->setTickInterval(step_value);
|
||||
slider->setValue(
|
||||
static_cast<int>((option.value[i].float_value - option.min_value[i].float_value) / step_value));
|
||||
connect(slider, &QSlider::valueChanged, [this, &option, i, slider_label](int value) {
|
||||
const float new_value = std::clamp(option.min_value[i].float_value +
|
||||
(static_cast<float>(value) * option.step_value[i].float_value),
|
||||
option.min_value[i].float_value, option.max_value[i].float_value);
|
||||
option.value[i].float_value = new_value;
|
||||
slider_label->setText(QString::number(new_value));
|
||||
configChanged();
|
||||
});
|
||||
connect(this, &PostProcessingShaderConfigWidget::resettingtoDefaults,
|
||||
[&option, i, slider, slider_label, step_value]() {
|
||||
QSignalBlocker sb(slider);
|
||||
slider->setValue(static_cast<int>(
|
||||
(option.default_value[i].float_value - option.min_value[i].float_value) / step_value));
|
||||
slider_label->setText(QString::number(option.default_value[i].float_value));
|
||||
option.value = option.default_value;
|
||||
});
|
||||
}
|
||||
|
||||
row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::RestoreDefaults, this);
|
||||
connect(button_box, &QDialogButtonBox::clicked, this, &PostProcessingShaderConfigWidget::onResetToDefaultsClicked);
|
||||
m_layout->addWidget(button_box, row, 0, 1, -1);
|
||||
|
||||
row++;
|
||||
m_layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding), row, 0, 1, 3);
|
||||
}
|
||||
|
||||
void PostProcessingShaderConfigWidget::onResetToDefaultsClicked()
|
||||
{
|
||||
resettingtoDefaults();
|
||||
configChanged();
|
||||
}
|
||||
|
||||
PostProcessingShaderConfigDialog::PostProcessingShaderConfigDialog(QWidget* parent,
|
||||
PostProcessingShader* shader)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("%1 Shader Options").arg(QString::fromStdString(shader->GetName())));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
QGridLayout* layout = new QGridLayout(this);
|
||||
m_widget = new PostProcessingShaderConfigWidget(this, shader);
|
||||
layout->addWidget(m_widget);
|
||||
|
||||
connect(m_widget, &PostProcessingShaderConfigWidget::configChanged, this,
|
||||
&PostProcessingShaderConfigDialog::onConfigChanged);
|
||||
|
||||
QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Close, this);
|
||||
connect(button_box, &QDialogButtonBox::rejected, this, &PostProcessingShaderConfigDialog::onCloseClicked);
|
||||
m_widget->getLayout()->addWidget(button_box, m_widget->getLayout()->rowCount() - 1, 2, 1, 2);
|
||||
}
|
||||
|
||||
PostProcessingShaderConfigDialog::~PostProcessingShaderConfigDialog() = default;
|
||||
|
||||
void PostProcessingShaderConfigDialog::onConfigChanged()
|
||||
{
|
||||
configChanged();
|
||||
}
|
||||
|
||||
void PostProcessingShaderConfigDialog::onCloseClicked()
|
||||
{
|
||||
done(0);
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/postprocessing_shader.h"
|
||||
|
||||
#include <QtWidgets/QDialog>
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
class QGridLayout;
|
||||
|
||||
class PostProcessingShaderConfigWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PostProcessingShaderConfigWidget(QWidget* parent, PostProcessingShader* shader);
|
||||
~PostProcessingShaderConfigWidget();
|
||||
|
||||
QGridLayout* getLayout() { return m_layout; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void configChanged();
|
||||
void resettingtoDefaults();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onResetToDefaultsClicked();
|
||||
|
||||
protected:
|
||||
void createUi();
|
||||
|
||||
PostProcessingShader* m_shader;
|
||||
QGridLayout* m_layout;
|
||||
};
|
||||
|
||||
class PostProcessingShaderConfigDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PostProcessingShaderConfigDialog(QWidget* parent, PostProcessingShader* shader);
|
||||
~PostProcessingShaderConfigDialog();
|
||||
|
||||
Q_SIGNALS:
|
||||
void configChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onConfigChanged();
|
||||
void onCloseClicked();
|
||||
|
||||
private:
|
||||
PostProcessingShaderConfigWidget* m_widget;
|
||||
};
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "util/ini_settings_interface.h"
|
||||
#include "util/input_manager.h"
|
||||
#include "util/platform_misc.h"
|
||||
#include "util/postprocessing.h"
|
||||
|
||||
#include "scmversion/scmversion.h"
|
||||
|
||||
@ -947,7 +948,20 @@ void EmuThread::reloadPostProcessingShaders()
|
||||
return;
|
||||
}
|
||||
|
||||
System::ReloadPostProcessingShaders();
|
||||
if (System::IsValid())
|
||||
PostProcessing::ReloadShaders();
|
||||
}
|
||||
|
||||
void EmuThread::updatePostProcessingSettings()
|
||||
{
|
||||
if (!isOnThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "updatePostProcessingSettings", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (System::IsValid())
|
||||
PostProcessing::UpdateSettings();
|
||||
}
|
||||
|
||||
void EmuThread::clearInputBindStateFromSource(InputBindingKey key)
|
||||
|
@ -188,6 +188,7 @@ public Q_SLOTS:
|
||||
void setCheatEnabled(quint32 index, bool enabled);
|
||||
void applyCheat(quint32 index);
|
||||
void reloadPostProcessingShaders();
|
||||
void updatePostProcessingSettings();
|
||||
void clearInputBindStateFromSource(InputBindingKey key);
|
||||
|
||||
private Q_SLOTS:
|
||||
|
Reference in New Issue
Block a user