From 287758f15d07cb6e0c19d861d8134124361d2d30 Mon Sep 17 00:00:00 2001
From: Ryan Houdek <Sonicadvance1@gmail.com>
Date: Tue, 29 Jul 2014 12:14:25 -0500
Subject: [PATCH] Add the configuration dialog for post processing
 configuration options. Only enables the config button when the shader options
 available to it

---
 Source/Core/DolphinWX/CMakeLists.txt          |   1 +
 Source/Core/DolphinWX/DolphinWX.vcxproj       |   4 +-
 .../Core/DolphinWX/DolphinWX.vcxproj.filters  |   8 +-
 .../DolphinWX/PostProcessingConfigDiag.cpp    | 316 ++++++++++++++++++
 .../Core/DolphinWX/PostProcessingConfigDiag.h | 106 ++++++
 Source/Core/DolphinWX/VideoConfigDiag.cpp     |  13 +-
 Source/Core/DolphinWX/VideoConfigDiag.h       |   9 +
 7 files changed, 454 insertions(+), 3 deletions(-)
 create mode 100644 Source/Core/DolphinWX/PostProcessingConfigDiag.cpp
 create mode 100644 Source/Core/DolphinWX/PostProcessingConfigDiag.h

diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt
index 302a27df28..613041de50 100644
--- a/Source/Core/DolphinWX/CMakeLists.txt
+++ b/Source/Core/DolphinWX/CMakeLists.txt
@@ -62,6 +62,7 @@ set(GUI_SRCS
 	MemoryCards/WiiSaveCrypted.cpp
 	NetWindow.cpp
 	PatchAddEdit.cpp
+	PostProcessingConfigDiag.cpp
 	SoftwareVideoConfigDialog.cpp
 	TASInputDlg.cpp
 	VideoConfigDiag.cpp
diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj b/Source/Core/DolphinWX/DolphinWX.vcxproj
index e62e2f2e43..52a13521ce 100644
--- a/Source/Core/DolphinWX/DolphinWX.vcxproj
+++ b/Source/Core/DolphinWX/DolphinWX.vcxproj
@@ -97,6 +97,7 @@
     </ClCompile>
     <ClCompile Include="TASInputDlg.cpp" />
     <ClCompile Include="VideoConfigDiag.cpp" />
+    <ClCompile Include="PostProcessingConfigDiag.cpp" />
     <ClCompile Include="WiimoteConfigDiag.cpp" />
     <ClCompile Include="WXInputBase.cpp" />
     <ClCompile Include="WxUtils.cpp" />
@@ -144,6 +145,7 @@
     <ClInclude Include="stdafx.h" />
     <ClInclude Include="TASInputDlg.h" />
     <ClInclude Include="VideoConfigDiag.h" />
+    <ClInclude Include="PostProcessingConfigDiag.h" />
     <ClInclude Include="WiimoteConfigDiag.h" />
     <ClInclude Include="WXInputBase.h" />
     <ClInclude Include="WxUtils.h" />
@@ -228,4 +230,4 @@
     <Message Text="Copy: @(BinaryFiles) -&gt; $(BinaryOutputDir)" Importance="High" />
     <Copy SourceFiles="@(BinaryFiles)" DestinationFolder="$(BinaryOutputDir)" />
   </Target>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters
index b9910845a8..59be1c3188 100644
--- a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters
+++ b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters
@@ -93,6 +93,9 @@
     <ClCompile Include="Debugger\DebuggerPanel.cpp">
       <Filter>GUI\Video</Filter>
     </ClCompile>
+    <ClCompile Include="PostProcessingConfigDiag.cpp">
+      <Filter>GUI\Video</Filter>
+    </ClCompile>
     <ClCompile Include="VideoConfigDiag.cpp">
       <Filter>GUI\Video</Filter>
     </ClCompile>
@@ -217,6 +220,9 @@
     <ClInclude Include="Debugger\DebuggerPanel.h">
       <Filter>GUI\Video</Filter>
     </ClInclude>
+    <ClInclude Include="PostProcessingConfigDiag.h">
+      <Filter>GUI\Video</Filter>
+    </ClInclude>
     <ClInclude Include="VideoConfigDiag.h">
       <Filter>GUI\Video</Filter>
     </ClInclude>
@@ -296,4 +302,4 @@
       <Filter>Resources</Filter>
     </Image>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp b/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp
new file mode 100644
index 0000000000..031c19f19d
--- /dev/null
+++ b/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp
@@ -0,0 +1,316 @@
+// Copyright 2013 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <math.h>
+#include <unordered_map>
+
+#include <wx/button.h>
+#include <wx/notebook.h>
+#include <wx/panel.h>
+#include <wx/sizer.h>
+#include <wx/slider.h>
+#include <wx/stattext.h>
+#include <wx/textctrl.h>
+
+#include "Common/StringUtil.h"
+
+#include "DolphinWX/PostProcessingConfigDiag.h"
+
+#include "VideoCommon/RenderBase.h"
+
+PostProcessingConfigDiag::PostProcessingConfigDiag(wxWindow* parent, const std::string& shader)
+	: wxDialog(parent, -1,
+		wxString::Format(_("Post Processing Shader Configuration"))),
+	  m_shader(shader)
+{
+	// Depending on if we are running already, either use the one from the videobackend
+	// or generate our own.
+	if (g_renderer && g_renderer->GetPostProcessor())
+	{
+		m_post_processor = g_renderer->GetPostProcessor()->GetConfig();
+	}
+	else
+	{
+		m_post_processor = new PostProcessingShaderConfiguration();
+		m_post_processor->LoadShader(m_shader);
+	}
+
+	// Create our UI classes
+	const PostProcessingShaderConfiguration::ConfigMap& config_map = m_post_processor->GetOptions();
+	for (const auto& it : config_map)
+	{
+		if (it.second.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL)
+		{
+			ConfigGrouping* group = new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_TOGGLE,
+				it.second.m_gui_name, it.first, it.second.m_dependent_option,
+				&it.second);
+			m_config_map[it.first] = group;
+		}
+		else
+		{
+			ConfigGrouping* group = new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_SLIDER,
+				it.second.m_gui_name, it.first, it.second.m_dependent_option,
+				&it.second);
+			m_config_map[it.first] = group;
+		}
+	}
+
+	// Arrange our vectors based on dependency
+	for (const auto& it : m_config_map)
+	{
+		const std::string parent_name = it.second->GetParent();
+		if (parent_name.size())
+		{
+			// Since it depends on a different object, push it to a parent's object
+			m_config_map[parent_name]->AddChild(m_config_map[it.first]);
+		}
+		else
+		{
+			// It doesn't have a child, just push it to the vector
+			m_config_groups.push_back(m_config_map[it.first]);
+		}
+	}
+
+	// Generate our UI
+	wxNotebook* const notebook = new wxNotebook(this, -1);
+	wxPanel* const page_general = new wxPanel(notebook, -1);
+	wxFlexGridSizer* const szr_general = new wxFlexGridSizer(2, 5, 5);
+
+	// Now let's actually populate our window with our information
+	bool add_general_page = false;
+	for (const auto& it : m_config_groups)
+	{
+		if (it->HasChildren())
+		{
+			// Options with children get their own tab
+			wxPanel* const page_option = new wxPanel(notebook, -1);
+			wxFlexGridSizer* const szr_option = new wxFlexGridSizer(2, 10, 5);
+			it->GenerateUI(this, page_option, szr_option);
+
+			// Add all the children
+			for (const auto& child : it->GetChildren())
+			{
+				child->GenerateUI(this, page_option, szr_option);
+			}
+			page_option->SetSizerAndFit(szr_option);
+			notebook->AddPage(page_option, _(it->GetGUIName()));
+		}
+		else
+		{
+			// Options with no children go in to the general tab
+			if (!add_general_page)
+			{
+				// Make it so it doesn't show up if there aren't any options without children.
+				add_general_page = true;
+			}
+			it->GenerateUI(this, page_general, szr_general);
+		}
+	}
+
+	if (add_general_page)
+	{
+		page_general->SetSizerAndFit(szr_general);
+		notebook->InsertPage(0, page_general, _("General"));
+	}
+
+	// Close Button
+	wxButton* const btn_close = new wxButton(this, wxID_OK, _("Close"));
+	btn_close->Bind(wxEVT_BUTTON, &PostProcessingConfigDiag::Event_ClickClose, this);
+
+	Bind(wxEVT_CLOSE_WINDOW, &PostProcessingConfigDiag::Event_Close, this);
+
+	wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL);
+	szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5);
+	szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5);
+
+	SetSizerAndFit(szr_main);
+	Center();
+	SetFocus();
+
+	UpdateWindowUI();
+}
+
+PostProcessingConfigDiag::~PostProcessingConfigDiag()
+{
+	m_post_processor->SaveOptionsConfiguration();
+	if (g_renderer && g_renderer->GetPostProcessor())
+		m_post_processor = nullptr;
+	else
+		delete m_post_processor;
+}
+
+void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDiag* dialog, wxWindow* parent, wxFlexGridSizer* sizer)
+{
+	if (m_type == WidgetType::TYPE_TOGGLE)
+	{
+		m_option_checkbox = new wxCheckBox(parent, wxID_ANY, _(m_gui_name));
+		m_option_checkbox->SetValue(m_config_option->m_bool_value);
+		m_option_checkbox->Bind(wxEVT_CHECKBOX, &PostProcessingConfigDiag::Event_CheckBox,
+		                        dialog, wxID_ANY, wxID_ANY, new UserEventData(m_option));
+
+		sizer->Add(m_option_checkbox);
+		sizer->AddStretchSpacer();
+	}
+	else
+	{
+		size_t vector_size = 0;
+		if (m_config_option->m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER)
+			vector_size = m_config_option->m_integer_values.size();
+		else
+			vector_size = m_config_option->m_float_values.size();
+
+		wxFlexGridSizer* const szr_values = new wxFlexGridSizer(vector_size + 1, 0, 0);
+		wxStaticText* const option_static_text = new wxStaticText(parent, wxID_ANY, _(m_gui_name));
+		sizer->Add(option_static_text);
+
+		for (size_t i = 0; i < vector_size; ++i)
+		{
+			// wxSlider uses a signed integer for it's minimum and maximum values
+			// This won't work for floats.
+			// Let's determine how many steps we can take and use that instead.
+			int steps = 0;
+			int current_value = 0;
+			std::string string_value;
+			if (m_config_option->m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER)
+			{
+				// Find out our range by taking the max subtracting the minimum.
+				double range = m_config_option->m_integer_max_values[i] - m_config_option->m_integer_min_values[i];
+
+				// How many steps we have is the range divided by the step interval configured.
+				// This may not be 100% spot on accurate since developers can have odd stepping intervals set.
+				// Round up so if it is outside our range, then set it to the minimum or maximum
+				steps = ceil(range / (double)m_config_option->m_integer_step_values[i]);
+
+				// Default value is just the currently set value here
+				current_value = m_config_option->m_integer_values[i];
+				string_value = std::to_string(m_config_option->m_integer_values[i]);
+			}
+			else
+			{
+				// Same as above but with floats
+				float range = m_config_option->m_float_max_values[i] - m_config_option->m_float_min_values[i];
+				steps = ceil(range / m_config_option->m_float_step_values[i]);
+
+				// We need to convert our default float value from a float to the nearest step value range
+				current_value = (m_config_option->m_float_values[i] / m_config_option->m_float_step_values[i]);
+				string_value = std::to_string(m_config_option->m_float_values[i]);
+			}
+
+			wxSlider* slider = new wxSlider(parent, wxID_ANY, current_value, 0, steps,
+			                                wxDefaultPosition, wxSize(200, -1), wxSL_HORIZONTAL | wxSL_BOTTOM);
+			wxTextCtrl* text_ctrl = new wxTextCtrl(parent, wxID_ANY, string_value);
+
+			// Disable the textctrl, it's only there to show the absolute value from the slider
+			text_ctrl->Enable(false);
+
+			// wxWidget takes over the pointer provided to it in the event handler.
+			// This won't be a memory leak, it'll be destroyed on dialog close.
+			slider->Bind(wxEVT_SLIDER, &PostProcessingConfigDiag::Event_Slider,
+					 dialog, wxID_ANY, wxID_ANY, new UserEventData(m_option));
+
+			m_option_sliders.push_back(slider);
+			m_option_text_ctrls.push_back(text_ctrl);
+		}
+
+		if (vector_size == 1)
+		{
+			szr_values->Add(m_option_sliders[0], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
+			szr_values->Add(m_option_text_ctrls[0]);
+
+			sizer->Add(szr_values);
+		}
+		else
+		{
+			wxFlexGridSizer* const szr_inside = new wxFlexGridSizer(2, 0, 0);
+			for (size_t i = 0; i < vector_size; ++i)
+			{
+				szr_inside->Add(m_option_sliders[i], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
+				szr_inside->Add(m_option_text_ctrls[i]);
+			}
+
+			szr_values->Add(szr_inside);
+			sizer->Add(szr_values);
+		}
+	}
+}
+
+void PostProcessingConfigDiag::ConfigGrouping::EnableDependentChildren(bool enable)
+{
+	// Enable or disable all the children
+	for (auto& it : m_children)
+	{
+		if (it->m_type == ConfigGrouping::WidgetType::TYPE_TOGGLE)
+		{
+			it->m_option_checkbox->Enable(enable);
+		}
+		else
+		{
+			for (auto& slider : it->m_option_sliders)
+				slider->Enable(enable);
+		}
+		// Set this objects children as well
+		it->EnableDependentChildren(enable);
+	}
+}
+
+void PostProcessingConfigDiag::Event_CheckBox(wxCommandEvent &ev)
+{
+	UserEventData* config_option = (UserEventData*)ev.GetEventUserData();
+	ConfigGrouping* config = m_config_map[config_option->GetData()];
+
+	m_post_processor->SetOptionb(config->GetOption(), ev.IsChecked());
+
+	config->EnableDependentChildren(ev.IsChecked());
+
+	ev.Skip();
+}
+
+void PostProcessingConfigDiag::Event_Slider(wxCommandEvent &ev)
+{
+	UserEventData* config_option = (UserEventData*)ev.GetEventUserData();
+	ConfigGrouping* config = m_config_map[config_option->GetData()];
+
+	const auto& option_data = m_post_processor->GetOption(config->GetOption());
+
+	size_t vector_size = 0;
+	if (option_data.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER)
+		vector_size = option_data.m_integer_values.size();
+	else
+		vector_size = option_data.m_float_values.size();
+
+	for (size_t i = 0; i < vector_size; ++i)
+	{
+		// Got to do this garbage again.
+		// Convert current step in to the real range value
+		int current_step = config->GetSliderValue(i);
+		std::string string_value;
+		if (option_data.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER)
+		{
+			s32 value = option_data.m_integer_step_values[i] * current_step + option_data.m_integer_min_values[i];
+			m_post_processor->SetOptioni(config->GetOption(), i, value);
+			string_value = std::to_string(value);
+
+		}
+		else
+		{
+			float value = option_data.m_float_step_values[i] * current_step + option_data.m_float_min_values[i];
+			m_post_processor->SetOptionf(config->GetOption(), i, value);
+			string_value = std::to_string(value);
+		}
+		// Update the text box to include the new value
+		config->SetSliderText(i, string_value);
+	}
+	ev.Skip();
+}
+
+void PostProcessingConfigDiag::Event_ClickClose(wxCommandEvent&)
+{
+	Close();
+}
+
+void PostProcessingConfigDiag::Event_Close(wxCloseEvent& ev)
+{
+	EndModal(wxID_OK);
+}
+
diff --git a/Source/Core/DolphinWX/PostProcessingConfigDiag.h b/Source/Core/DolphinWX/PostProcessingConfigDiag.h
new file mode 100644
index 0000000000..dabf44468b
--- /dev/null
+++ b/Source/Core/DolphinWX/PostProcessingConfigDiag.h
@@ -0,0 +1,106 @@
+// Copyright 2013 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <wx/button.h>
+#include <wx/checkbox.h>
+#include <wx/dialog.h>
+#include <wx/sizer.h>
+#include <wx/slider.h>
+#include <wx/stattext.h>
+#include <wx/textctrl.h>
+
+#include "VideoCommon/PostProcessing.h"
+
+class PostProcessingConfigDiag : public wxDialog
+{
+public:
+	PostProcessingConfigDiag(wxWindow* parent, const std::string& shader);
+	~PostProcessingConfigDiag();
+
+private:
+
+	// This is literally the stupidest thing ever
+	// wxWidgets takes ownership of any pointer given to a event handler
+	// Instead of passing them a pointer to a std::string, we wrap around it here.
+	class UserEventData : public wxObject
+	{
+	public:
+		UserEventData(const std::string& data) : m_data(data) {}
+		const std::string& GetData() { return m_data; }
+	private:
+		const std::string m_data;
+	};
+
+	class ConfigGrouping
+	{
+	public:
+		enum WidgetType
+		{
+			TYPE_TOGGLE,
+			TYPE_SLIDER,
+		};
+
+		ConfigGrouping(WidgetType type, const std::string& gui_name,
+		               const std::string& option_name, const std::string& parent,
+				   const PostProcessingShaderConfiguration::ConfigurationOption* config_option)
+			: m_type(type), m_gui_name(gui_name),
+			  m_option(option_name), m_parent(parent),
+			  m_config_option(config_option) {}
+
+		void AddChild(ConfigGrouping* child) { m_children.push_back(child); }
+		bool HasChildren() { return m_children.size() != 0; }
+		std::vector<ConfigGrouping*>& GetChildren() { return m_children; }
+
+		// Gets the string that is shown in the UI for the option
+		const std::string& GetGUIName() { return m_gui_name; }
+		// Gets the option name for use in the shader
+		// Also is a unique identifier for the option's configuration
+		const std::string& GetOption() { return m_option; }
+		// Gets the option name of the parent of this option
+		const std::string& GetParent() { return m_parent; }
+
+		void GenerateUI(PostProcessingConfigDiag* dialog, wxWindow* parent, wxFlexGridSizer* sizer);
+
+		void EnableDependentChildren(bool enable);
+
+		int GetSliderValue(const int index) { return m_option_sliders[index]->GetValue(); }
+		void SetSliderText(const int index, const std::string& text) { m_option_text_ctrls[index]->SetValue(text); }
+
+	private:
+		const WidgetType m_type;
+		const std::string m_gui_name;
+		const std::string m_option;
+		const std::string m_parent;
+		const PostProcessingShaderConfiguration::ConfigurationOption* m_config_option;
+
+		// For TYPE_TOGGLE
+		wxCheckBox* m_option_checkbox;
+
+		// For TYPE_SLIDER
+		// Can have up to 4
+		std::vector<wxSlider*> m_option_sliders;
+		std::vector<wxTextCtrl*> m_option_text_ctrls;
+
+		std::vector<ConfigGrouping*> m_children;
+	};
+
+	// WX UI things
+	void Event_Close(wxCloseEvent&);
+	void Event_ClickClose(wxCommandEvent&);
+	void Event_Slider(wxCommandEvent &ev);
+	void Event_CheckBox(wxCommandEvent &ev);
+
+	const std::string& m_shader;
+	PostProcessingShaderConfiguration* m_post_processor;
+
+	std::map<std::string, ConfigGrouping*> m_config_map;
+	std::vector<ConfigGrouping*> m_config_groups;
+};
+
diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp
index 13f3dad9b4..0bd5a8ccff 100644
--- a/Source/Core/DolphinWX/VideoConfigDiag.cpp
+++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp
@@ -1,3 +1,7 @@
+// Copyright 2013 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
 #include <map>
 #include <string>
 #include <utility>
@@ -32,6 +36,7 @@
 #include "DolphinWX/VideoConfigDiag.h"
 #include "DolphinWX/WxUtils.h"
 #include "VideoBackends/OGL/main.h"
+#include "VideoCommon/PostProcessing.h"
 #include "VideoCommon/VideoBackendBase.h"
 #include "VideoCommon/VideoConfig.h"
 
@@ -401,10 +406,13 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
 	// postproc shader
 	if (vconfig.backend_info.PPShaders.size())
 	{
+		wxFlexGridSizer* const szr_pp = new wxFlexGridSizer(3, 5, 5);
 		wxChoice *const choice_ppshader = new wxChoice(page_enh, -1);
 		RegisterControl(choice_ppshader, wxGetTranslation(ppshader_desc));
 		choice_ppshader->AppendString(_("(off)"));
 
+		button_config_pp = new wxButton(page_enh, wxID_ANY, _("Config"));
+
 		for (const std::string& shader : vconfig.backend_info.PPShaders)
 		{
 			choice_ppshader->AppendString(StrToWxStr(shader));
@@ -421,9 +429,12 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
 		button_config_pp->Enable(postprocessing_shader.HasOptions());
 
 		choice_ppshader->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_PPShader, this);
+		button_config_pp->Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_ConfigurePPShader, this);
 
 		szr_enh->Add(new wxStaticText(page_enh, -1, _("Post-Processing Effect:")), 1, wxALIGN_CENTER_VERTICAL, 0);
-		szr_enh->Add(choice_ppshader);
+		szr_pp->Add(choice_ppshader);
+		szr_pp->Add(button_config_pp);
+		szr_enh->Add(szr_pp);
 	}
 
 	// Scaled copy, PL, Bilinear filter
diff --git a/Source/Core/DolphinWX/VideoConfigDiag.h b/Source/Core/DolphinWX/VideoConfigDiag.h
index 6802f0be84..261fa2f6ec 100644
--- a/Source/Core/DolphinWX/VideoConfigDiag.h
+++ b/Source/Core/DolphinWX/VideoConfigDiag.h
@@ -1,9 +1,14 @@
+// Copyright 2013 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
 #pragma once
 
 #include <cstddef>
 #include <map>
 #include <string>
 #include <vector>
+#include <wx/button.h>
 #include <wx/checkbox.h>
 #include <wx/choice.h>
 #include <wx/defs.h>
@@ -22,7 +27,9 @@
 #include "Core/ConfigManager.h"
 #include "Core/Core.h"
 #include "Core/CoreParameter.h"
+#include "DolphinWX/PostProcessingConfigDiag.h"
 #include "DolphinWX/WxUtils.h"
+#include "VideoCommon/PostProcessing.h"
 #include "VideoCommon/VideoBackendBase.h"
 #include "VideoCommon/VideoConfig.h"
 
@@ -201,6 +208,8 @@ protected:
 	wxStaticText* text_aamode;
 	SettingChoice* choice_aamode;
 
+	wxButton* button_config_pp;
+
 	SettingCheckBox* borderless_fullscreen;
 
 	SettingRadioButton* efbcopy_texture;