Qt: Add work in progress interface

This commit is contained in:
Connor McLaughlin 2021-12-13 22:12:54 +10:00 committed by refractionpcsx2
parent c2ca0852d9
commit 93f9ae8a31
509 changed files with 17724 additions and 0 deletions

3
3rdparty/qt/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/*
!.gitignore
!README.md

11
3rdparty/qt/README.md vendored Normal file
View File

@ -0,0 +1,11 @@
# PCSX2 Qt Binaries
## Windows
You can download the binaries from https://github.com/PCSX2/pcsx2-windows-dependencies
Grab the latest release without symbols (or, if you want to debug Qt, with symbols), and extract it to this directory.
## Linux
TODO

656
PCSX2_qt.sln Normal file
View File

@ -0,0 +1,656 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31606.5
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rdparty", "3rdparty", "{78EBE642-7A4D-4EA7-86BE-5639C6646C38}"
ProjectSection(SolutionItems) = preProject
3rdparty\svn_readme.txt = 3rdparty\svn_readme.txt
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{2D6F0A62-A247-4CCF-947F-FCD54BE16103}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "3rdparty\soundtouch\SoundTouch.vcxproj", "{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "3rdparty\zlib\zlib.vcxproj", "{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bin2cpp", "tools\bin2cpp\bin2c.vcxproj", "{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "3rdparty\libjpeg\libjpeg.vcxproj", "{BC236261-77E8-4567-8D09-45CD02965EB6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wx30_config", "3rdparty\wxwidgets3.0\build\msw\wx30_config.vcxproj", "{01F4CE10-2CFB-41A8-B41F-E54337868A1D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wx30_base", "3rdparty\wxwidgets3.0\build\msw\wx30_base.vcxproj", "{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "3rdparty\libpng\projects\vstudio\libpng\libpng.vcxproj", "{D6973076-9317-4EF2-A0B8-B7A18AC0713E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pthreads4w", "3rdparty\pthreads4w\build\pthreads4w.vcxproj", "{0FAE817D-9A32-4830-857E-81DA57246E16}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "baseclasses", "3rdparty\baseclasses\baseclasses.vcxproj", "{27F17499-A372-4408-8AFA-4F9F4584FBD3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblzma", "3rdparty\xz\liblzma.vcxproj", "{12728250-16EC-4DC6-94D7-E21DD88947F8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "3rdparty\fmt\fmt.vcxproj", "{449AD25E-424A-4714-BABC-68706CDCC33B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsamplerate", "3rdparty\libsamplerate\libsamplerate.vcxproj", "{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libchdr", "3rdparty\libchdr\libchdr.vcxproj", "{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpgd", "3rdparty\jpgd\jpgd.vcxproj", "{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcxproj", "{4639972E-424E-4E13-8B07-CA403C481346}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcsx2core", "pcsx2\pcsx2core.vcxproj", "{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glad", "3rdparty\glad\glad.vcxproj", "{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imgui", "3rdparty\imgui\imgui.vcxproj", "{88FB34EC-845E-4F21-A552-F1573B9ED167}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcsx2-qt", "pcsx2-qt\pcsx2-qt.vcxproj", "{2A016F21-87AE-4154-8271-1F57E91408E9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleini", "3rdparty\simpleini\simpleini.vcxproj", "{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cubeb", "3rdparty\cubeb\cubeb.vcxproj", "{BF74C473-DC04-44B3-92E8-4145F4E77342}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ryml", "3rdparty\rapidyaml\ryml.vcxproj", "{DE9653B6-17DD-356A-9EE0-28A731772587}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang", "3rdparty\glslang\glslang.vcxproj", "{EF6834A9-11F3-4331-BC34-21B325ABB180}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug AVX2|Win32 = Debug AVX2|Win32
Debug AVX2|x64 = Debug AVX2|x64
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Devel AVX2|Win32 = Devel AVX2|Win32
Devel AVX2|x64 = Devel AVX2|x64
Devel|Win32 = Devel|Win32
Devel|x64 = Devel|x64
Release AVX2|Win32 = Release AVX2|Win32
Release AVX2|x64 = Release AVX2|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug AVX2|Win32.Build.0 = Debug|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug AVX2|x64.ActiveCfg = Debug|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug AVX2|x64.Build.0 = Debug|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug|Win32.ActiveCfg = Debug|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug|Win32.Build.0 = Debug|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug|x64.ActiveCfg = Debug|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug|x64.Build.0 = Debug|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel AVX2|Win32.Build.0 = Devel|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel AVX2|x64.ActiveCfg = Devel|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel AVX2|x64.Build.0 = Devel|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel|Win32.ActiveCfg = Devel|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel|Win32.Build.0 = Devel|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel|x64.ActiveCfg = Devel|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel|x64.Build.0 = Devel|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release AVX2|Win32.ActiveCfg = Release|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release AVX2|Win32.Build.0 = Release|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release AVX2|x64.ActiveCfg = Release|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release AVX2|x64.Build.0 = Release|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release|Win32.ActiveCfg = Release|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release|Win32.Build.0 = Release|Win32
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release|x64.ActiveCfg = Release|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release|x64.Build.0 = Release|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug AVX2|Win32.Build.0 = Debug|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug AVX2|x64.ActiveCfg = Debug|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug AVX2|x64.Build.0 = Debug|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug|Win32.ActiveCfg = Debug|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug|Win32.Build.0 = Debug|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug|x64.ActiveCfg = Debug|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug|x64.Build.0 = Debug|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel AVX2|Win32.Build.0 = Devel|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel AVX2|x64.ActiveCfg = Devel|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel AVX2|x64.Build.0 = Devel|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel|Win32.ActiveCfg = Devel|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel|Win32.Build.0 = Devel|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel|x64.ActiveCfg = Devel|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel|x64.Build.0 = Devel|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release AVX2|Win32.ActiveCfg = Release|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release AVX2|Win32.Build.0 = Release|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release AVX2|x64.ActiveCfg = Release|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release AVX2|x64.Build.0 = Release|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release|Win32.ActiveCfg = Release|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release|Win32.Build.0 = Release|Win32
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release|x64.ActiveCfg = Release|x64
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release|x64.Build.0 = Release|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug AVX2|Win32.Build.0 = Debug|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug AVX2|x64.ActiveCfg = Debug|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug AVX2|x64.Build.0 = Debug|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug|Win32.ActiveCfg = Debug|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug|Win32.Build.0 = Debug|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug|x64.ActiveCfg = Debug|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug|x64.Build.0 = Debug|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel AVX2|Win32.Build.0 = Devel|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel AVX2|x64.ActiveCfg = Devel|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel AVX2|x64.Build.0 = Devel|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel|Win32.ActiveCfg = Devel|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel|Win32.Build.0 = Devel|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel|x64.ActiveCfg = Devel|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel|x64.Build.0 = Devel|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release AVX2|Win32.ActiveCfg = Release|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release AVX2|Win32.Build.0 = Release|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release AVX2|x64.ActiveCfg = Release|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release AVX2|x64.Build.0 = Release|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release|Win32.ActiveCfg = Release|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release|Win32.Build.0 = Release|Win32
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release|x64.ActiveCfg = Release|x64
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release|x64.Build.0 = Release|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug AVX2|Win32.Build.0 = Debug|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug AVX2|x64.ActiveCfg = Debug|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug AVX2|x64.Build.0 = Debug|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug|Win32.ActiveCfg = Debug|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug|Win32.Build.0 = Debug|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug|x64.ActiveCfg = Debug|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug|x64.Build.0 = Debug|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel AVX2|Win32.Build.0 = Devel|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel AVX2|x64.ActiveCfg = Devel|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel AVX2|x64.Build.0 = Devel|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel|Win32.ActiveCfg = Devel|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel|Win32.Build.0 = Devel|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel|x64.ActiveCfg = Devel|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel|x64.Build.0 = Devel|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release AVX2|Win32.ActiveCfg = Release|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release AVX2|Win32.Build.0 = Release|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release AVX2|x64.ActiveCfg = Release|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release AVX2|x64.Build.0 = Release|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release|Win32.ActiveCfg = Release|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release|Win32.Build.0 = Release|Win32
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release|x64.ActiveCfg = Release|x64
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release|x64.Build.0 = Release|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug AVX2|Win32.Build.0 = Debug|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug AVX2|x64.ActiveCfg = Debug|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug AVX2|x64.Build.0 = Debug|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|Win32.ActiveCfg = Debug|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|Win32.Build.0 = Debug|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.ActiveCfg = Debug|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.Build.0 = Debug|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel AVX2|Win32.Build.0 = Devel|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel AVX2|x64.ActiveCfg = Devel|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel AVX2|x64.Build.0 = Devel|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel|Win32.ActiveCfg = Devel|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel|Win32.Build.0 = Devel|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel|x64.ActiveCfg = Devel|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel|x64.Build.0 = Devel|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release AVX2|Win32.ActiveCfg = Release|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release AVX2|Win32.Build.0 = Release|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release AVX2|x64.ActiveCfg = Release|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release AVX2|x64.Build.0 = Release|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|Win32.ActiveCfg = Release|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|Win32.Build.0 = Release|Win32
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.ActiveCfg = Release|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.Build.0 = Release|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug AVX2|Win32.Build.0 = Debug|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug AVX2|x64.ActiveCfg = Debug|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug AVX2|x64.Build.0 = Debug|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|Win32.ActiveCfg = Debug|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|Win32.Build.0 = Debug|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.ActiveCfg = Debug|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.Build.0 = Debug|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel AVX2|Win32.Build.0 = Devel|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel AVX2|x64.ActiveCfg = Devel|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel AVX2|x64.Build.0 = Devel|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel|Win32.ActiveCfg = Devel|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel|Win32.Build.0 = Devel|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel|x64.ActiveCfg = Devel|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel|x64.Build.0 = Devel|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release AVX2|Win32.ActiveCfg = Release|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release AVX2|Win32.Build.0 = Release|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release AVX2|x64.ActiveCfg = Release|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release AVX2|x64.Build.0 = Release|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|Win32.ActiveCfg = Release|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|Win32.Build.0 = Release|Win32
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.ActiveCfg = Release|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.Build.0 = Release|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug AVX2|Win32.Build.0 = Debug|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug AVX2|x64.ActiveCfg = Debug|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug AVX2|x64.Build.0 = Debug|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|Win32.ActiveCfg = Debug|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|Win32.Build.0 = Debug|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel AVX2|Win32.Build.0 = Devel|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel AVX2|x64.ActiveCfg = Devel|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel AVX2|x64.Build.0 = Devel|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel|Win32.ActiveCfg = Devel|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel|Win32.Build.0 = Devel|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel|x64.ActiveCfg = Devel|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel|x64.Build.0 = Devel|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release AVX2|Win32.ActiveCfg = Release|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release AVX2|Win32.Build.0 = Release|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release AVX2|x64.ActiveCfg = Release|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release AVX2|x64.Build.0 = Release|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|Win32.ActiveCfg = Release|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|Win32.Build.0 = Release|Win32
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.Build.0 = Release|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug AVX2|Win32.Build.0 = Debug|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug AVX2|x64.ActiveCfg = Debug|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug AVX2|x64.Build.0 = Debug|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug|Win32.ActiveCfg = Debug|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug|Win32.Build.0 = Debug|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug|x64.ActiveCfg = Debug|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug|x64.Build.0 = Debug|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel AVX2|Win32.Build.0 = Devel|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel AVX2|x64.ActiveCfg = Devel|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel AVX2|x64.Build.0 = Devel|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel|Win32.ActiveCfg = Devel|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel|Win32.Build.0 = Devel|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel|x64.ActiveCfg = Devel|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel|x64.Build.0 = Devel|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release AVX2|Win32.ActiveCfg = Release|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release AVX2|Win32.Build.0 = Release|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release AVX2|x64.ActiveCfg = Release|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release AVX2|x64.Build.0 = Release|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release|Win32.ActiveCfg = Release|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release|Win32.Build.0 = Release|Win32
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release|x64.ActiveCfg = Release|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release|x64.Build.0 = Release|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug AVX2|Win32.Build.0 = Debug|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug AVX2|x64.ActiveCfg = Debug|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug AVX2|x64.Build.0 = Debug|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug|Win32.ActiveCfg = Debug|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug|Win32.Build.0 = Debug|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug|x64.ActiveCfg = Debug|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug|x64.Build.0 = Debug|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel AVX2|Win32.Build.0 = Devel|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel AVX2|x64.ActiveCfg = Devel|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel AVX2|x64.Build.0 = Devel|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel|Win32.ActiveCfg = Devel|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel|Win32.Build.0 = Devel|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel|x64.ActiveCfg = Devel|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel|x64.Build.0 = Devel|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release AVX2|Win32.ActiveCfg = Release|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release AVX2|Win32.Build.0 = Release|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release AVX2|x64.ActiveCfg = Release|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release AVX2|x64.Build.0 = Release|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release|Win32.ActiveCfg = Release|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release|Win32.Build.0 = Release|Win32
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release|x64.ActiveCfg = Release|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release|x64.Build.0 = Release|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug AVX2|Win32.Build.0 = Debug|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug AVX2|x64.ActiveCfg = Debug|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug AVX2|x64.Build.0 = Debug|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|Win32.ActiveCfg = Debug|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|Win32.Build.0 = Debug|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|x64.ActiveCfg = Debug|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|x64.Build.0 = Debug|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel AVX2|Win32.Build.0 = Devel|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel AVX2|x64.ActiveCfg = Devel|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel AVX2|x64.Build.0 = Devel|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel|Win32.ActiveCfg = Devel|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel|Win32.Build.0 = Devel|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel|x64.ActiveCfg = Devel|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel|x64.Build.0 = Devel|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release AVX2|Win32.ActiveCfg = Release|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release AVX2|Win32.Build.0 = Release|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release AVX2|x64.ActiveCfg = Release|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release AVX2|x64.Build.0 = Release|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|Win32.ActiveCfg = Release|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|Win32.Build.0 = Release|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.ActiveCfg = Release|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.Build.0 = Release|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug AVX2|Win32.Build.0 = Debug|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug AVX2|x64.ActiveCfg = Debug|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug AVX2|x64.Build.0 = Debug|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug|Win32.ActiveCfg = Debug|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug|Win32.Build.0 = Debug|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug|x64.ActiveCfg = Debug|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug|x64.Build.0 = Debug|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel AVX2|Win32.Build.0 = Devel|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel AVX2|x64.ActiveCfg = Devel|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel AVX2|x64.Build.0 = Devel|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel|Win32.ActiveCfg = Devel|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel|Win32.Build.0 = Devel|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel|x64.ActiveCfg = Devel|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel|x64.Build.0 = Devel|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release AVX2|Win32.ActiveCfg = Release|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release AVX2|Win32.Build.0 = Release|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release AVX2|x64.ActiveCfg = Release|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release AVX2|x64.Build.0 = Release|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release|Win32.ActiveCfg = Release|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release|Win32.Build.0 = Release|Win32
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release|x64.ActiveCfg = Release|x64
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release|x64.Build.0 = Release|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug AVX2|Win32.Build.0 = Debug|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug AVX2|x64.ActiveCfg = Debug|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug AVX2|x64.Build.0 = Debug|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug|Win32.ActiveCfg = Debug|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug|Win32.Build.0 = Debug|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug|x64.ActiveCfg = Debug|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug|x64.Build.0 = Debug|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel AVX2|Win32.Build.0 = Devel|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel AVX2|x64.ActiveCfg = Devel|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel AVX2|x64.Build.0 = Devel|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel|Win32.ActiveCfg = Devel|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel|Win32.Build.0 = Devel|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel|x64.ActiveCfg = Devel|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel|x64.Build.0 = Devel|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release AVX2|Win32.ActiveCfg = Release|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release AVX2|Win32.Build.0 = Release|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release AVX2|x64.ActiveCfg = Release|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release AVX2|x64.Build.0 = Release|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|Win32.ActiveCfg = Release|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|Win32.Build.0 = Release|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|x64.ActiveCfg = Release|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|x64.Build.0 = Release|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|Win32.Build.0 = Debug|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|x64.ActiveCfg = Debug|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|x64.Build.0 = Debug|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug|Win32.ActiveCfg = Debug|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug|Win32.Build.0 = Debug|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug|x64.ActiveCfg = Debug|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug|x64.Build.0 = Debug|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel AVX2|Win32.Build.0 = Devel|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel AVX2|x64.ActiveCfg = Devel|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel AVX2|x64.Build.0 = Devel|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel|Win32.ActiveCfg = Devel|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel|Win32.Build.0 = Devel|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel|x64.ActiveCfg = Devel|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel|x64.Build.0 = Devel|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release AVX2|Win32.ActiveCfg = Release|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release AVX2|Win32.Build.0 = Release|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release AVX2|x64.ActiveCfg = Release|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release AVX2|x64.Build.0 = Release|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release|Win32.ActiveCfg = Release|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release|Win32.Build.0 = Release|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release|x64.ActiveCfg = Release|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release|x64.Build.0 = Release|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug AVX2|Win32.Build.0 = Debug|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug AVX2|x64.ActiveCfg = Debug|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug AVX2|x64.Build.0 = Debug|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug|Win32.ActiveCfg = Debug|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug|Win32.Build.0 = Debug|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug|x64.ActiveCfg = Debug|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug|x64.Build.0 = Debug|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel AVX2|Win32.Build.0 = Devel|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel AVX2|x64.ActiveCfg = Devel|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel AVX2|x64.Build.0 = Devel|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel|Win32.ActiveCfg = Devel|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel|Win32.Build.0 = Devel|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel|x64.ActiveCfg = Devel|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel|x64.Build.0 = Devel|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release AVX2|Win32.ActiveCfg = Release|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release AVX2|Win32.Build.0 = Release|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release AVX2|x64.ActiveCfg = Release|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release AVX2|x64.Build.0 = Release|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release|Win32.ActiveCfg = Release|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release|Win32.Build.0 = Release|Win32
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release|x64.ActiveCfg = Release|x64
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release|x64.Build.0 = Release|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Debug AVX2|Win32.Build.0 = Debug|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Debug AVX2|x64.ActiveCfg = Debug|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Debug AVX2|x64.Build.0 = Debug|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Debug|Win32.ActiveCfg = Debug|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Debug|Win32.Build.0 = Debug|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Debug|x64.ActiveCfg = Debug|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Debug|x64.Build.0 = Debug|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Devel AVX2|Win32.Build.0 = Devel|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Devel AVX2|x64.ActiveCfg = Devel|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Devel AVX2|x64.Build.0 = Devel|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Devel|Win32.ActiveCfg = Devel|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Devel|Win32.Build.0 = Devel|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Devel|x64.ActiveCfg = Devel|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Devel|x64.Build.0 = Devel|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Release AVX2|Win32.ActiveCfg = Release|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Release AVX2|Win32.Build.0 = Release|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Release AVX2|x64.ActiveCfg = Release|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Release AVX2|x64.Build.0 = Release|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Release|Win32.ActiveCfg = Release|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Release|Win32.Build.0 = Release|Win32
{4639972E-424E-4E13-8B07-CA403C481346}.Release|x64.ActiveCfg = Release|x64
{4639972E-424E-4E13-8B07-CA403C481346}.Release|x64.Build.0 = Release|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Debug AVX2|Win32.ActiveCfg = Debug AVX2|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Debug AVX2|Win32.Build.0 = Debug AVX2|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Debug AVX2|x64.ActiveCfg = Debug AVX2|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Debug AVX2|x64.Build.0 = Debug AVX2|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Debug|Win32.ActiveCfg = Debug|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Debug|Win32.Build.0 = Debug|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Debug|x64.ActiveCfg = Debug|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Debug|x64.Build.0 = Debug|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Devel AVX2|Win32.ActiveCfg = Devel AVX2|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Devel AVX2|Win32.Build.0 = Devel AVX2|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Devel AVX2|x64.ActiveCfg = Devel AVX2|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Devel AVX2|x64.Build.0 = Devel AVX2|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Devel|Win32.ActiveCfg = Devel|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Devel|Win32.Build.0 = Devel|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Devel|x64.ActiveCfg = Devel|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Devel|x64.Build.0 = Devel|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Release AVX2|Win32.ActiveCfg = Release AVX2|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Release AVX2|Win32.Build.0 = Release AVX2|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Release AVX2|x64.ActiveCfg = Release AVX2|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Release AVX2|x64.Build.0 = Release AVX2|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Release|Win32.ActiveCfg = Release|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Release|Win32.Build.0 = Release|Win32
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Release|x64.ActiveCfg = Release|x64
{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}.Release|x64.Build.0 = Release|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug AVX2|Win32.Build.0 = Debug|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug AVX2|x64.ActiveCfg = Debug|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug AVX2|x64.Build.0 = Debug|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug|Win32.ActiveCfg = Debug|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug|Win32.Build.0 = Debug|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug|x64.ActiveCfg = Debug|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug|x64.Build.0 = Debug|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel AVX2|Win32.Build.0 = Devel|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel AVX2|x64.ActiveCfg = Devel|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel AVX2|x64.Build.0 = Devel|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel|Win32.ActiveCfg = Devel|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel|Win32.Build.0 = Devel|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel|x64.ActiveCfg = Devel|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel|x64.Build.0 = Devel|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release AVX2|Win32.ActiveCfg = Release|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release AVX2|Win32.Build.0 = Release|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release AVX2|x64.ActiveCfg = Release|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release AVX2|x64.Build.0 = Release|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|Win32.ActiveCfg = Release|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|Win32.Build.0 = Release|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|x64.ActiveCfg = Release|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|x64.Build.0 = Release|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug AVX2|Win32.Build.0 = Debug|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug AVX2|x64.ActiveCfg = Debug|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug AVX2|x64.Build.0 = Debug|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug|Win32.ActiveCfg = Debug|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug|Win32.Build.0 = Debug|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug|x64.ActiveCfg = Debug|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug|x64.Build.0 = Debug|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel AVX2|Win32.Build.0 = Devel|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel AVX2|x64.ActiveCfg = Devel|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel AVX2|x64.Build.0 = Devel|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel|Win32.ActiveCfg = Devel|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel|Win32.Build.0 = Devel|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel|x64.ActiveCfg = Devel|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel|x64.Build.0 = Devel|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release AVX2|Win32.ActiveCfg = Release|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release AVX2|Win32.Build.0 = Release|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release AVX2|x64.ActiveCfg = Release|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release AVX2|x64.Build.0 = Release|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release|Win32.ActiveCfg = Release|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release|Win32.Build.0 = Release|Win32
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release|x64.ActiveCfg = Release|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release|x64.Build.0 = Release|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug AVX2|Win32.ActiveCfg = Debug AVX2|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug AVX2|Win32.Build.0 = Debug AVX2|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug AVX2|x64.ActiveCfg = Debug AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug AVX2|x64.Build.0 = Debug AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug|Win32.ActiveCfg = Debug|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug|Win32.Build.0 = Debug|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug|x64.ActiveCfg = Debug|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug|x64.Build.0 = Debug|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel AVX2|Win32.ActiveCfg = Devel AVX2|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel AVX2|Win32.Build.0 = Devel AVX2|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel AVX2|x64.ActiveCfg = Devel AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel AVX2|x64.Build.0 = Devel AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel|Win32.ActiveCfg = Devel|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel|Win32.Build.0 = Devel|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel|x64.ActiveCfg = Devel|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel|x64.Build.0 = Devel|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release AVX2|Win32.ActiveCfg = Release AVX2|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release AVX2|Win32.Build.0 = Release AVX2|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release AVX2|x64.ActiveCfg = Release AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release AVX2|x64.Build.0 = Release AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release|Win32.ActiveCfg = Release|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release|Win32.Build.0 = Release|Win32
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release|x64.ActiveCfg = Release|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release|x64.Build.0 = Release|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|Win32.Build.0 = Debug|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|x64.ActiveCfg = Debug|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|x64.Build.0 = Debug|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|Win32.ActiveCfg = Debug|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|Win32.Build.0 = Debug|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|x64.ActiveCfg = Debug|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|x64.Build.0 = Debug|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|Win32.Build.0 = Devel|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|x64.ActiveCfg = Devel|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|x64.Build.0 = Devel|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|Win32.ActiveCfg = Devel|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|Win32.Build.0 = Devel|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|x64.ActiveCfg = Devel|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|x64.Build.0 = Devel|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|Win32.ActiveCfg = Release|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|Win32.Build.0 = Release|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|x64.ActiveCfg = Release|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|x64.Build.0 = Release|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|Win32.ActiveCfg = Release|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|Win32.Build.0 = Release|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|x64.ActiveCfg = Release|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|x64.Build.0 = Release|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|Win32.Build.0 = Debug|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|x64.ActiveCfg = Debug|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|x64.Build.0 = Debug|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|Win32.ActiveCfg = Debug|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|Win32.Build.0 = Debug|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|x64.ActiveCfg = Debug|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|x64.Build.0 = Debug|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|Win32.Build.0 = Devel|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|x64.ActiveCfg = Devel|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|x64.Build.0 = Devel|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|Win32.ActiveCfg = Devel|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|Win32.Build.0 = Devel|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|x64.ActiveCfg = Devel|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|x64.Build.0 = Devel|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|Win32.ActiveCfg = Release|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|Win32.Build.0 = Release|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|x64.ActiveCfg = Release|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|x64.Build.0 = Release|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|Win32.ActiveCfg = Release|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|Win32.Build.0 = Release|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|x64.ActiveCfg = Release|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|x64.Build.0 = Release|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|Win32.Build.0 = Debug|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|x64.ActiveCfg = Debug|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|x64.Build.0 = Debug|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|Win32.ActiveCfg = Debug|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|Win32.Build.0 = Debug|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|x64.ActiveCfg = Debug|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|x64.Build.0 = Debug|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|Win32.Build.0 = Devel|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|x64.ActiveCfg = Devel|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|x64.Build.0 = Devel|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|Win32.ActiveCfg = Devel|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|Win32.Build.0 = Devel|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|x64.ActiveCfg = Devel|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|x64.Build.0 = Devel|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|Win32.ActiveCfg = Release|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|Win32.Build.0 = Release|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|x64.ActiveCfg = Release|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|x64.Build.0 = Release|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|Win32.ActiveCfg = Release|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|Win32.Build.0 = Release|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|x64.ActiveCfg = Release|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|x64.Build.0 = Release|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug AVX2|Win32.Build.0 = Debug|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug AVX2|x64.ActiveCfg = Debug|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug AVX2|x64.Build.0 = Debug|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug|Win32.ActiveCfg = Debug|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug|Win32.Build.0 = Debug|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug|x64.ActiveCfg = Debug|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug|x64.Build.0 = Debug|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel AVX2|Win32.Build.0 = Devel|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel AVX2|x64.ActiveCfg = Devel|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel AVX2|x64.Build.0 = Devel|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel|Win32.ActiveCfg = Devel|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel|Win32.Build.0 = Devel|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel|x64.ActiveCfg = Devel|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel|x64.Build.0 = Devel|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release AVX2|Win32.ActiveCfg = Release|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release AVX2|Win32.Build.0 = Release|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release AVX2|x64.ActiveCfg = Release|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release AVX2|x64.Build.0 = Release|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release|Win32.ActiveCfg = Release|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release|Win32.Build.0 = Release|Win32
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release|x64.ActiveCfg = Release|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213} = {2D6F0A62-A247-4CCF-947F-FCD54BE16103}
{BC236261-77E8-4567-8D09-45CD02965EB6} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{01F4CE10-2CFB-41A8-B41F-E54337868A1D} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{0FAE817D-9A32-4830-857E-81DA57246E16} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{27F17499-A372-4408-8AFA-4F9F4584FBD3} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{12728250-16EC-4DC6-94D7-E21DD88947F8} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{449AD25E-424A-4714-BABC-68706CDCC33B} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{88FB34EC-845E-4F21-A552-F1573B9ED167} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{BF74C473-DC04-44B3-92E8-4145F4E77342} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{DE9653B6-17DD-356A-9EE0-28A731772587} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{EF6834A9-11F3-4331-BC34-21B325ABB180} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0BC474EA-3628-45D3-9DBC-E22D0B7E0F77}
EndGlobalSection
EndGlobal

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

@ -232,6 +232,10 @@ if(NOT USE_SYSTEM_YAML)
endif()
endif()
if(QT_BUILD)
find_package(Qt6 COMPONENTS Core Gui Widgets Network LinguistTools REQUIRED)
endif()
add_subdirectory(3rdparty/libchdr/libchdr EXCLUDE_FROM_ALL)
if(USE_NATIVE_TOOLS)

View File

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="UserMacros">
<BinaryOutputDir>$(SolutionDir)bin\</BinaryOutputDir>
<QTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)3rdparty\qt\6.2.2\msvc2019_64\</QTDIRDefault>
<QTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)3rdparty\qt\6.2.2\msvc2019_arm64\</QTDIRDefault>
<QTDIR Condition="Exists('$(QTDIRDefault)') And ('$(QTDIR)'=='' Or !Exists('$(QTDIR)'))">$(QTDIRDefault)</QTDIR>
<QTDIR Condition="Exists('$(QTDIR)') And !HasTrailingSlash('$(QTDIR)')">$(QTDIR)\</QTDIR>
<QTDIRHost>$(SolutionDir)3rdparty\qt\6.2.2\msvc2019_64\</QTDIRHost>
<QtDirValid>false</QtDirValid>
<QtDirValid Condition="Exists('$(QTDIR)')">true</QtDirValid>
<QtIncludeDir>$(QTDIR)include\</QtIncludeDir>
<QtLibDir>$(QTDIR)lib\</QtLibDir>
<QtBinDir>$(QTDIR)bin\</QtBinDir>
<QtHostBinDir>$(QTDIRHost)bin\</QtHostBinDir>
<QtPluginsDir>$(QTDIR)plugins\</QtPluginsDir>
<QtTranslationsDir>$(QTDIR)translations\</QtTranslationsDir>
<QtToolOutDir>$(IntDir)</QtToolOutDir>
<QtMocOutPrefix>$(QtToolOutDir)moc_</QtMocOutPrefix>
<QtTsOutDir>$(BinaryOutputDir)translations\</QtTsOutDir>
<QtDebugSuffix>d</QtDebugSuffix>
<QtLibSuffix Condition="$(Configuration.Contains(Debug))">$(QtDebugSuffix)</QtLibSuffix>
<QtPluginFolder>QtPlugins</QtPluginFolder>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions Condition="!$(Configuration.Contains(Debug))">QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(QtToolOutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(QtIncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(QtLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>Qt6Core$(QtLibSuffix).lib;Qt6Gui$(QtLibSuffix).lib;Qt6Widgets$(QtLibSuffix).lib;Qt6Network$(QtLibSuffix).lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<!--Passes all .qrc files to rcc and puts output in the build directory-->
<ItemGroup>
<ResFiles Include="$(MSBuildProjectDirectory)\**\*.qrc" />
</ItemGroup>
<Target Name="QtResource"
BeforeTargets="ClCompile"
Inputs="@(ResFiles)"
Condition="'@(QtResource)'!=''"
Outputs="@(ResFiles->'$(QtToolOutDir)qrc_%(Filename).cpp')">
<Message Text="rcc %(ResFiles.Filename)" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not valid (download/extract the zip)" />
<MakeDir Directories="$(QtToolOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)rcc.exe&quot; &quot;%(ResFiles.FullPath)&quot; -o &quot;$(QtToolOutDir)qrc_%(ResFiles.Filename).cpp&quot;" />
</Target>
<Target Name="QtResourceClean">
<Delete Files="@(ResFiles->'$(QtToolOutDir)qrc_%(Filename).cpp')" />
</Target>
<!--Passes all .ui files to uic and puts output in the build directory-->
<ItemGroup>
<UiFiles Include="$(MSBuildProjectDirectory)\**\*.ui" />
</ItemGroup>
<Target Name="QtUi"
BeforeTargets="ClCompile"
Inputs="@(UiFiles)"
Condition="'@(QtUi)'!=''"
Outputs="@(UiFiles->'$(QtToolOutDir)ui_%(Filename).h')">
<Message Text="uic %(UiFiles.Filename)" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not valid (download/extract the zip)" />
<MakeDir Directories="$(QtToolOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)uic.exe&quot; &quot;%(UiFiles.FullPath)&quot; -o &quot;$(QtToolOutDir)ui_%(UiFiles.Filename).h&quot;" />
</Target>
<Target Name="QtUiClean">
<Delete Files="@(UiFiles->'$(QtToolOutDir)ui_%(Filename).h')" />
</Target>
<!--Compile files needed to MOC and output in the build directory-->
<!--TODO find a way to autocreate from ClCompile settings-->
<PropertyGroup>
<MocDefines></MocDefines>
<MocDefines Condition="!$(Configuration.Contains(Debug))">-DQT_NO_DEBUG -DNDEBUG $(MocDefines)</MocDefines>
<MocIncludes>"-I$(QtIncludeDir)" "-I$(SolutionDir)pcsx2" "-I$(SolutionDir)" -I.</MocIncludes>
</PropertyGroup>
<Target Name="QtMoc"
BeforeTargets="ClCompile"
Condition="'@(QtMoc)'!=''"
Inputs="%(QtMoc.Identity);%(QtMoc.AdditionalDependencies);$(MSBuildProjectFile)"
Outputs="$(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp">
<Message Text="moc %(QtMoc.Filename) $(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" />
<MakeDir Directories="$(QtToolOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)moc.exe&quot; &quot;%(QtMoc.FullPath)&quot; -b &quot;PrecompiledHeader.h&quot; -o &quot;$(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp&quot; -f%(QtMoc.Filename)%(QtMoc.Extension) $(MocDefines) $(MocIncludes)" />
</Target>
<ItemGroup>
<MocOutputs Include="$(QtToolOutDir)moc_*.cpp" />
</ItemGroup>
<Target Name="QtMocClean">
<Delete Files="@(MocOutputs)" />
</Target>
<!--Expose the new targets to VS-->
<ItemGroup>
<PropertyPageSchema Include="$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml" />
<AvailableItemName Include="QtResource">
<Targets>QtResource</Targets>
</AvailableItemName>
<AvailableItemName Include="QtUi">
<Targets>QtUi</Targets>
</AvailableItemName>
<AvailableItemName Include="QtMoc">
<Targets>QtMoc</Targets>
</AvailableItemName>
<AvailableItemName Include="QtTs">
<Targets>QtTs</Targets>
</AvailableItemName>
</ItemGroup>
<!--Copy the needed dlls-->
<ItemGroup>
<QtLibNames Include="Qt6Core$(QtLibSuffix);Qt6Gui$(QtLibSuffix);Qt6Widgets$(QtLibSuffix);Qt6Network$(QtLibSuffix);Qt6Svg$(QtLibSuffix)" />
<QtDlls Include="@(QtLibNames -> '$(QtBinDir)%(Identity).dll')" />
<!--Filter plugins to copy based on the observation that all debug versions end in "d"-->
<QtAllPlugins Include="$(QtPluginsDir)**\*$(QtLibSuffix).dll" />
<QtPlugins Condition="$(Configuration.Contains(Debug))" Include="@(QtAllPlugins)" />
<QtPlugins Condition="!$(Configuration.Contains(Debug))" Exclude="$(QtPluginsDir)**\*$(QtDebugSuffix).dll" Include="@(QtAllPlugins)" />
<QtPluginsDest Include="@(QtPlugins -> '$(BinaryOutputDir)$(QtPluginFolder)\%(RecursiveDir)%(Filename)%(Extension)')" />
</ItemGroup>
<PropertyGroup>
<QtConfFile>$(BinaryOutputDir)qt.conf</QtConfFile>
</PropertyGroup>
<Target Name="QtCopyBinaries"
AfterTargets="Build"
Inputs="@(QtDlls);@(QtPlugins)"
Outputs="@(QtDlls -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)');@(QtPlugins -> '$(BinaryOutputDir)$(QtPluginFolder)\%(RecursiveDir)%(Filename)%(Extension)')">
<Message Text="Copying Qt .dlls" Importance="High" />
<Copy
SourceFiles="@(QtDlls)"
DestinationFolder="$(BinaryOutputDir)"
SkipUnchangedFiles="true"
/>
<Copy
SourceFiles="@(QtPlugins)"
DestinationFiles="@(QtPluginsDest)"
SkipUnchangedFiles="true"
/>
</Target>
<Target Name="QtCreateConf"
BeforeTargets="QtCopyBinaries"
Condition="!Exists('$(QtConfFile)')">
<!--
Create a file which tells Qt where to look for "plugins".
Otherwise Qt only looks in ./<subtype>/type.dll instead of ./$(QtPluginFolder)/<subtype>/type.dll, which is messy
-->
<WriteLinesToFile
File="$(QtConfFile)"
Lines="[Paths];Plugins = ./$(QtPluginFolder)"
Overwrite="true"
/>
</Target>
<!--Copies base translation files-->
<ItemGroup>
<BaseTsFiles Include="$(QtTranslationsDir)\*.qm" />
</ItemGroup>
<Target Name="QtCopyBaseTranslations"
AfterTargets="Build"
Inputs="@(BaseTsFiles)"
Outputs="@(BaseTsFiles -> '$(QtTsOutDir)%(RecursiveDir)%(Filename)%(Extension)')">
<Message Text="Copying base translation files" Importance="High" />
<Copy
SourceFiles="@(BaseTsFiles)"
DestinationFolder="$(QtTsOutDir)"
SkipUnchangedFiles="true"
/>
</Target>
<!--Compiles all translation files-->
<ItemGroup>
<TsFiles Include="$(MSBuildProjectDirectory)\**\*.ts" />
</ItemGroup>
<Target Name="QtTs"
BeforeTargets="ClCompile"
Inputs="@(TsFiles)"
Condition="'@(QtTs)'!=''"
Outputs="@(TsFiles->'$(QtTsOutDir)%(Filename).qm')">
<Message Text="lrelease %(TsFiles.Filename)" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not valid (download/extract the zip)" />
<MakeDir Directories="$(QtTsOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)lrelease.exe&quot; &quot;%(TsFiles.FullPath)&quot; -qm &quot;$(QtTsOutDir)%(TsFiles.Filename).qm&quot;" />
</Target>
<ItemGroup>
<TsOutputs Include="$(QtTsOutDir)*.qm" />
</ItemGroup>
<Target Name="QtTsClean">
<Delete Files="@(TsOutputs)" />
</Target>
</Project>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CleanDependsOn>QtResourceClean;QtUiClean;QtMocClean;QtTsClean;$(CleanDependsOn)</CleanDependsOn>
<!--
<ComputeLinkInputsTargets>$(ComputeLinkInputsTargets);QtComputeMocOutput;</ComputeLinkInputsTargets>
<ComputeLibInputsTargets>$(ComputeLibInputsTargets);QtComputeMocOutput;</ComputeLibInputsTargets>
-->
</PropertyGroup>
</Project>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties">
<ItemType Name="QtResource" DisplayName="Qt Resource File" />
<ItemType Name="QtUi" DisplayName="Qt User Interface File" />
<ItemType Name="QtMoc" DisplayName="Qt Meta Object File" />
<ItemType Name="QtTs" DisplayName="Qt Translation File" />
<ContentType Name="QtUi" DisplayName="Qt User Interface Compiler" />
<ContentType Name="QtResource" DisplayName="Qt Resource Compiler" />
<ContentType Name="QtMoc" DisplayName="Qt Meta Object Compiler" />
<ContentType Name="QtTs" DisplayName="Qt Translation Compiler" />
<FileExtension Name="*.qrc" ContentType="QtResource" />
<FileExtension Name="*.ui" ContentType="QtUi" />
<FileExtension Name="*.ts" ContentType="QtTs" />
</ProjectSchemaDefinitions>

76
pcsx2-qt/AboutDialog.cpp Normal file
View File

@ -0,0 +1,76 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "AboutDialog.h"
#include "QtUtils.h"
#include "svnrev.h"
#include <QtCore/QString>
#include <QtWidgets/QDialog>
AboutDialog::AboutDialog(QWidget* parent)
: QDialog(parent)
{
m_ui.setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setFixedSize(geometry().width(), geometry().height());
m_ui.scmversion->setTextInteractionFlags(Qt::TextSelectableByMouse);
m_ui.scmversion->setText(GIT_REV);
m_ui.links->setTextInteractionFlags(Qt::TextBrowserInteraction);
m_ui.links->setOpenExternalLinks(true);
m_ui.links->setText(QStringLiteral(
R"(<a href="%1">%2</a> | <a href="%3">%4</a> | <a href="%5">%6</a> | <a href="%7">%8</a>)")
.arg(getWebsiteUrl())
.arg(tr("Website"))
.arg(getSupportForumsUrl())
.arg(tr("Support Forums"))
.arg(getGitHubRepositoryUrl())
.arg(tr("GitHub Repository"))
.arg(getLicenseUrl())
.arg(tr("License")));
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &QDialog::close);
}
AboutDialog::~AboutDialog() = default;
QString AboutDialog::getWebsiteUrl()
{
return QStringLiteral("https://pcsx2.net/");
}
QString AboutDialog::getSupportForumsUrl()
{
return QStringLiteral("https://forums.pcsx2.net/");
}
QString AboutDialog::getGitHubRepositoryUrl()
{
return QStringLiteral("https://github.com/PCSX2/pcsx2");
}
QString AboutDialog::getLicenseUrl()
{
return QStringLiteral("https://github.com/PCSX2/pcsx2/blob/master/pcsx2/Docs/License.txt");
}
QString AboutDialog::getDiscordServerUrl()
{
return QStringLiteral("https://discord.com/invite/TCz3t9k");
}

37
pcsx2-qt/AboutDialog.h Normal file
View File

@ -0,0 +1,37 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ui_AboutDialog.h"
#include <QtWidgets/QDialog>
class AboutDialog final : public QDialog
{
Q_OBJECT
public:
explicit AboutDialog(QWidget* parent = nullptr);
~AboutDialog();
static QString getWebsiteUrl();
static QString getSupportForumsUrl();
static QString getGitHubRepositoryUrl();
static QString getLicenseUrl();
static QString getDiscordServerUrl();
private:
Ui::AboutDialog m_ui;
};

168
pcsx2-qt/AboutDialog.ui Normal file
View File

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutDialog</class>
<widget class="QDialog" name="AboutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>576</width>
<height>294</height>
</rect>
</property>
<property name="windowTitle">
<string>About PCSX2</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="icon">
<property name="maximumSize">
<size>
<width>260</width>
<height>260</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources/resources.qrc">:/icons/logo.png</pixmap>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="scmversion">
<property name="text">
<string>SCM Version</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="description">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;PCSX2 is a free and open-source PlayStation 2 (PS2) emulator. Its purpose is to emulate the PS2's hardware, using a combination of MIPS CPU Interpreters, Recompilers and a Virtual Machine which manages hardware states and PS2 system memory. This allows you to play PS2 games on your PC, with many additional features and benefits.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignJustify|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="disclaimer">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;PlayStation 2 and PS2 are registered trademarks of Sony Interactive Entertainment. This application is not affiliated in any way with Sony Interactive Entertainment.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignJustify|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="links">
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
<property name="centerButtons">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="resources/resources.qrc"/>
<include location="resources/icons.qrc"/>
</resources>
<connections/>
</ui>

102
pcsx2-qt/CMakeLists.txt Normal file
View File

@ -0,0 +1,102 @@
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
add_executable(pcsx2-qt)
if (PACKAGE_MODE)
install(TARGETS pcsx2-qt DESTINATION ${CMAKE_INSTALL_BINDIR})
else()
install(TARGETS pcsx2-qt DESTINATION ${CMAKE_SOURCE_DIR}/bin)
endif()
target_sources(pcsx2-qt PRIVATE
AboutDialog.cpp
AboutDialog.h
AboutDialog.ui
DisplayWidget.cpp
DisplayWidget.h
EmuThread.cpp
EmuThread.h
Main.cpp
MainWindow.cpp
MainWindow.h
MainWindow.ui
PrecompiledHeader.cpp
PrecompiledHeader.h
QtHost.cpp
QtHost.h
QtKeyCodes.cpp
QtUtils.cpp
QtUtils.h
SettingWidgetBinder.h
GameList/GameListModel.cpp
GameList/GameListModel.h
GameList/GameListRefreshThread.cpp
GameList/GameListRefreshThread.h
GameList/GameListWidget.cpp
GameList/GameListWidget.h
Settings/AdvancedSystemSettingsWidget.cpp
Settings/AdvancedSystemSettingsWidget.h
Settings/AdvancedSystemSettingsWidget.ui
Settings/BIOSSettingsWidget.cpp
Settings/BIOSSettingsWidget.h
Settings/BIOSSettingsWidget.ui
Settings/ControllerBindingWidget.ui
Settings/ControllerBindingWidget_DualShock2.ui
Settings/ControllerBindingWidgets.cpp
Settings/ControllerBindingWidgets.h
Settings/ControllerGlobalSettingsWidget.cpp
Settings/ControllerGlobalSettingsWidget.h
Settings/ControllerGlobalSettingsWidget.ui
Settings/ControllerSettingsDialog.cpp
Settings/ControllerSettingsDialog.h
Settings/ControllerSettingsDialog.ui
Settings/EmulationSettingsWidget.cpp
Settings/EmulationSettingsWidget.h
Settings/EmulationSettingsWidget.ui
Settings/GameFixSettingsWidget.cpp
Settings/GameFixSettingsWidget.h
Settings/GameFixSettingsWidget.ui
Settings/GameListSettingsWidget.cpp
Settings/GameListSettingsWidget.h
Settings/GameListSettingsWidget.ui
Settings/GraphicsSettingsWidget.cpp
Settings/GraphicsSettingsWidget.h
Settings/GraphicsSettingsWidget.ui
Settings/HotkeySettingsWidget.cpp
Settings/HotkeySettingsWidget.h
Settings/InputBindingDialog.cpp
Settings/InputBindingDialog.h
Settings/InputBindingDialog.ui
Settings/InputBindingWidget.cpp
Settings/InputBindingWidget.h
Settings/InterfaceSettingsWidget.cpp
Settings/InterfaceSettingsWidget.h
Settings/InterfaceSettingsWidget.ui
Settings/SettingsDialog.cpp
Settings/SettingsDialog.h
Settings/SettingsDialog.ui
Settings/SystemSettingsWidget.cpp
Settings/SystemSettingsWidget.h
Settings/SystemSettingsWidget.ui
resources/resources.qrc
)
target_precompile_headers(pcsx2-qt PRIVATE PrecompiledHeader.h)
target_include_directories(pcsx2-qt PRIVATE
${Qt6Gui_PRIVATE_INCLUDE_DIRS}
"${CMAKE_BINARY_DIR}/common/include"
"${CMAKE_SOURCE_DIR}/pcsx2"
"${CMAKE_SOURCE_DIR}/pcsx2-qt"
)
target_link_libraries(pcsx2-qt PRIVATE
PCSX2_FLAGS
PCSX2
Qt6::Core
Qt6::Gui
Qt6::Widgets
Qt6::Network
)

334
pcsx2-qt/DisplayWidget.cpp Normal file
View File

@ -0,0 +1,334 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "DisplayWidget.h"
#include "EmuThread.h"
#include "QtHost.h"
#include "pcsx2/GS/GSIntrin.h" // _BitScanForward
#include <QtCore/QDebug>
#include <QtGui/QGuiApplication>
#include <QtGui/QKeyEvent>
#include <QtGui/QScreen>
#include <QtGui/QWindow>
#include <QtGui/QWindowStateChangeEvent>
#include <cmath>
#if !defined(_WIN32) && !defined(APPLE)
#include <qpa/qplatformnativeinterface.h>
#endif
DisplayWidget::DisplayWidget(QWidget* parent)
: QWidget(parent)
{
// We want a native window for both D3D and OpenGL.
setAutoFillBackground(false);
setAttribute(Qt::WA_NativeWindow, true);
setAttribute(Qt::WA_NoSystemBackground, true);
setAttribute(Qt::WA_PaintOnScreen, true);
setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true);
}
DisplayWidget::~DisplayWidget() = default;
qreal DisplayWidget::devicePixelRatioFromScreen() const
{
QScreen* screen_for_ratio;
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
screen_for_ratio = windowHandle()->screen();
#else
screen_for_ratio = screen();
#endif
if (!screen_for_ratio)
screen_for_ratio = QGuiApplication::primaryScreen();
return screen_for_ratio ? screen_for_ratio->devicePixelRatio() : static_cast<qreal>(1);
}
int DisplayWidget::scaledWindowWidth() const
{
return static_cast<int>(std::ceil(static_cast<qreal>(width()) * devicePixelRatioFromScreen()));
}
int DisplayWidget::scaledWindowHeight() const
{
return static_cast<int>(std::ceil(static_cast<qreal>(height()) * devicePixelRatioFromScreen()));
}
std::optional<WindowInfo> DisplayWidget::getWindowInfo() const
{
WindowInfo wi;
// Windows and Apple are easy here since there's no display connection.
#if defined(_WIN32)
wi.type = WindowInfo::Type::Win32;
wi.window_handle = reinterpret_cast<void*>(winId());
#elif defined(__APPLE__)
wi.type = WindowInfo::Type::MacOS;
wi.window_handle = reinterpret_cast<void*>(winId());
#else
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
const QString platform_name = QGuiApplication::platformName();
if (platform_name == QStringLiteral("xcb"))
{
wi.type = WindowInfo::Type::X11;
wi.display_connection = pni->nativeResourceForWindow("display", windowHandle());
wi.window_handle = reinterpret_cast<void*>(winId());
}
else if (platform_name == QStringLiteral("wayland"))
{
wi.type = WindowInfo::Type::Wayland;
wi.display_connection = pni->nativeResourceForWindow("display", windowHandle());
wi.window_handle = pni->nativeResourceForWindow("surface", windowHandle());
}
else
{
qCritical() << "Unknown PNI platform " << platform_name;
return std::nullopt;
}
#endif
wi.surface_width = scaledWindowWidth();
wi.surface_height = scaledWindowHeight();
wi.surface_scale = devicePixelRatioFromScreen();
return wi;
}
void DisplayWidget::setRelativeMode(bool enabled)
{
if (m_relative_mouse_enabled == enabled)
return;
if (enabled)
{
m_relative_mouse_start_position = QCursor::pos();
const QPoint center_pos = mapToGlobal(QPoint(width() / 2, height() / 2));
QCursor::setPos(center_pos);
m_relative_mouse_last_position = center_pos;
grabMouse();
}
else
{
QCursor::setPos(m_relative_mouse_start_position);
releaseMouse();
}
m_relative_mouse_enabled = enabled;
}
QPaintEngine* DisplayWidget::paintEngine() const
{
return nullptr;
}
bool DisplayWidget::event(QEvent* event)
{
switch (event->type())
{
case QEvent::KeyPress:
case QEvent::KeyRelease:
{
const QKeyEvent* key_event = static_cast<QKeyEvent*>(event);
if (!key_event->isAutoRepeat())
{
emit windowKeyEvent(key_event->key(), static_cast<int>(key_event->modifiers()),
event->type() == QEvent::KeyPress);
}
return true;
}
case QEvent::MouseMove:
{
const QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
if (!m_relative_mouse_enabled)
{
const qreal dpr = devicePixelRatioFromScreen();
const QPoint mouse_pos = mouse_event->pos();
const int scaled_x = static_cast<int>(static_cast<qreal>(mouse_pos.x()) * dpr);
const int scaled_y = static_cast<int>(static_cast<qreal>(mouse_pos.y()) * dpr);
windowMouseMoveEvent(scaled_x, scaled_y);
}
else
{
const QPoint center_pos = mapToGlobal(QPoint((width() + 1) / 2, (height() + 1) / 2));
const QPoint mouse_pos = mapToGlobal(mouse_event->pos());
const int dx = mouse_pos.x() - center_pos.x();
const int dy = mouse_pos.y() - center_pos.y();
m_relative_mouse_last_position.setX(m_relative_mouse_last_position.x() + dx);
m_relative_mouse_last_position.setY(m_relative_mouse_last_position.y() + dy);
windowMouseMoveEvent(m_relative_mouse_last_position.x(), m_relative_mouse_last_position.y());
QCursor::setPos(center_pos);
}
return true;
}
case QEvent::MouseButtonPress:
case QEvent::MouseButtonDblClick:
case QEvent::MouseButtonRelease:
{
unsigned long button_index;
if (_BitScanForward(&button_index, static_cast<u32>(static_cast<const QMouseEvent*>(event)->button())))
emit windowMouseButtonEvent(static_cast<int>(button_index + 1u), event->type() != QEvent::MouseButtonRelease);
if (event->type() == QEvent::MouseButtonDblClick &&
static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton &&
Host::GetBoolSettingValue("UI", "DoubleClickTogglesFullscreen", true))
{
g_emu_thread->toggleFullscreen();
}
return true;
}
case QEvent::Wheel:
{
const QWheelEvent* wheel_event = static_cast<QWheelEvent*>(event);
emit windowMouseWheelEvent(wheel_event->angleDelta());
return true;
}
case QEvent::Resize:
{
QWidget::event(event);
emit windowResizedEvent(scaledWindowWidth(), scaledWindowHeight(), devicePixelRatioFromScreen());
return true;
}
case QEvent::Close:
{
emit windowClosedEvent();
QWidget::event(event);
return true;
}
case QEvent::WindowStateChange:
{
QWidget::event(event);
if (static_cast<QWindowStateChangeEvent*>(event)->oldState() & Qt::WindowMinimized)
emit windowRestoredEvent();
return true;
}
case QEvent::FocusIn:
{
QWidget::event(event);
emit windowFocusEvent();
return true;
}
case QEvent::ActivationChange:
{
QWidget::event(event);
if (isActiveWindow())
emit windowFocusEvent();
return true;
}
default:
return QWidget::event(event);
}
}
DisplayContainer::DisplayContainer()
: QStackedWidget(nullptr)
{
}
DisplayContainer::~DisplayContainer() = default;
bool DisplayContainer::IsNeeded(bool fullscreen, bool render_to_main)
{
#if defined(_WIN32) || defined(__APPLE__)
return false;
#else
if (fullscreen || render_to_main)
return false;
// We only need this on Wayland because of client-side decorations...
const QString platform_name = QGuiApplication::platformName();
return (platform_name == QStringLiteral("wayland"));
#endif
}
void DisplayContainer::setDisplayWidget(DisplayWidget* widget)
{
pxAssert(!m_display_widget);
m_display_widget = widget;
addWidget(widget);
}
DisplayWidget* DisplayContainer::removeDisplayWidget()
{
DisplayWidget* widget = m_display_widget;
pxAssert(widget);
m_display_widget = nullptr;
removeWidget(widget);
return widget;
}
bool DisplayContainer::event(QEvent* event)
{
const bool res = QStackedWidget::event(event);
if (!m_display_widget)
return res;
switch (event->type())
{
case QEvent::Close:
{
emit m_display_widget->windowClosedEvent();
}
break;
case QEvent::WindowStateChange:
{
if (static_cast<QWindowStateChangeEvent*>(event)->oldState() & Qt::WindowMinimized)
emit m_display_widget->windowRestoredEvent();
}
break;
case QEvent::FocusIn:
{
emit m_display_widget->windowFocusEvent();
}
break;
case QEvent::ActivationChange:
{
if (isActiveWindow())
emit m_display_widget->windowFocusEvent();
}
break;
default:
break;
}
return res;
}

77
pcsx2-qt/DisplayWidget.h Normal file
View File

@ -0,0 +1,77 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/WindowInfo.h"
#include <QtWidgets/QStackedWidget>
#include <QtWidgets/QWidget>
#include <optional>
class DisplayWidget final : public QWidget
{
Q_OBJECT
public:
explicit DisplayWidget(QWidget* parent);
~DisplayWidget();
QPaintEngine* paintEngine() const override;
int scaledWindowWidth() const;
int scaledWindowHeight() const;
qreal devicePixelRatioFromScreen() const;
std::optional<WindowInfo> getWindowInfo() const;
void setRelativeMode(bool enabled);
Q_SIGNALS:
void windowFocusEvent();
void windowResizedEvent(int width, int height, float scale);
void windowRestoredEvent();
void windowClosedEvent();
void windowKeyEvent(int key_code, int mods, bool pressed);
void windowMouseMoveEvent(int x, int y);
void windowMouseButtonEvent(int button, bool pressed);
void windowMouseWheelEvent(const QPoint& angle_delta);
protected:
bool event(QEvent* event) override;
private:
QPoint m_relative_mouse_start_position{};
QPoint m_relative_mouse_last_position{};
bool m_relative_mouse_enabled = false;
};
class DisplayContainer final : public QStackedWidget
{
Q_OBJECT
public:
DisplayContainer();
~DisplayContainer();
static bool IsNeeded(bool fullscreen, bool render_to_main);
void setDisplayWidget(DisplayWidget* widget);
DisplayWidget* removeDisplayWidget();
protected:
bool event(QEvent* event) override;
private:
DisplayWidget* m_display_widget = nullptr;
};

755
pcsx2-qt/EmuThread.cpp Normal file
View File

@ -0,0 +1,755 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include <QtWidgets/QApplication>
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/Exceptions.h"
#include "common/SettingsWrapper.h"
#include "common/StringUtil.h"
#include "pcsx2/CDVD/CDVD.h"
#include "pcsx2/Frontend/InputManager.h"
#include "pcsx2/Frontend/ImGuiManager.h"
#include "pcsx2/GS.h"
#include "pcsx2/HostDisplay.h"
#include "pcsx2/PAD/Host/PAD.h"
#include "pcsx2/PerformanceMetrics.h"
#include "pcsx2/VMManager.h"
#include "pcsx2/Frontend/OpenGLHostDisplay.h"
#ifdef _WIN32
#include "pcsx2/Frontend/D3D11HostDisplay.h"
#endif
#include "DisplayWidget.h"
#include "EmuThread.h"
#include "MainWindow.h"
#include "QtHost.h"
EmuThread* g_emu_thread = nullptr;
WindowInfo g_gs_window_info;
static std::unique_ptr<HostDisplay> s_host_display;
EmuThread::EmuThread(QThread* ui_thread)
: QThread()
, m_ui_thread(ui_thread)
{
}
EmuThread::~EmuThread() = default;
bool EmuThread::isOnEmuThread() const
{
return QThread::currentThread() == this;
}
void EmuThread::start()
{
pxAssertRel(!g_emu_thread, "Emu thread does not exist");
g_emu_thread = new EmuThread(QThread::currentThread());
g_emu_thread->QThread::start();
g_emu_thread->m_started_semaphore.acquire();
g_emu_thread->moveToThread(g_emu_thread);
g_main_window->connectVMThreadSignals(g_emu_thread);
}
void EmuThread::stop()
{
pxAssertRel(g_emu_thread, "Emu thread exists");
pxAssertRel(!g_emu_thread->isOnEmuThread(), "Not called on the emu thread");
QMetaObject::invokeMethod(g_emu_thread, &EmuThread::stopInThread, Qt::QueuedConnection);
while (g_emu_thread->isRunning())
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
}
void EmuThread::stopInThread()
{
if (VMManager::HasValidVM())
destroyVM();
m_event_loop->quit();
m_shutdown_flag.store(true);
}
void EmuThread::startVM(std::shared_ptr<VMBootParameters> boot_params)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "startVM", Qt::QueuedConnection,
Q_ARG(std::shared_ptr<VMBootParameters>, boot_params));
return;
}
pxAssertRel(!VMManager::HasValidVM(), "VM is shut down");
emit onVMStarting();
// create the display, this may take a while...
m_is_fullscreen = boot_params->fullscreen.value_or(QtHost::GetBaseBoolSettingValue("UI", "StartFullscreen", false));
m_is_rendering_to_main = !m_is_fullscreen && QtHost::GetBaseBoolSettingValue("UI", "RenderToMainWindow", true);
if (!VMManager::Initialize(*boot_params))
return;
VMManager::SetState(VMState::Running);
m_event_loop->quit();
}
void EmuThread::resetVM()
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, &EmuThread::resetVM, Qt::QueuedConnection);
return;
}
VMManager::Reset();
}
void EmuThread::setVMPaused(bool paused)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "setVMPaused", Qt::QueuedConnection, Q_ARG(bool, paused));
return;
}
VMManager::SetPaused(paused);
}
void EmuThread::shutdownVM(bool allow_save_to_state /* = true */, bool blocking /* = false */)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "shutdownVM", Qt::QueuedConnection, Q_ARG(bool, allow_save_to_state),
Q_ARG(bool, blocking));
if (blocking)
{
// we need to yield here, since the display gets destroyed
while (VMManager::HasValidVM())
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
}
return;
}
const VMState state = VMManager::GetState();
if (state == VMState::Paused)
m_event_loop->quit();
else if (state != VMState::Running)
return;
VMManager::SetState(VMState::Stopping);
}
void EmuThread::loadState(const QString& filename)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "loadState", Qt::QueuedConnection, Q_ARG(const QString&, filename));
return;
}
if (!VMManager::HasValidVM())
return;
VMManager::LoadState(filename.toUtf8().constData());
}
void EmuThread::loadStateFromSlot(qint32 slot)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "loadStateFromSlot", Qt::QueuedConnection, Q_ARG(qint32, slot));
return;
}
if (!VMManager::HasValidVM())
return;
VMManager::LoadStateFromSlot(slot);
}
void EmuThread::saveState(const QString& filename)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "saveState", Qt::QueuedConnection, Q_ARG(const QString&, filename));
return;
}
if (!VMManager::HasValidVM())
return;
if (!VMManager::SaveState(filename.toUtf8().constData()))
{
// this one is usually the result of a user-chosen path, so we can display a message box safely here
Console.Error("Failed to save state");
}
}
void EmuThread::saveStateToSlot(qint32 slot)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "saveStateToSlot", Qt::QueuedConnection, Q_ARG(qint32, slot));
return;
}
if (!VMManager::HasValidVM())
return;
VMManager::SaveStateToSlot(slot);
}
void EmuThread::run()
{
PerformanceMetrics::SetCPUThreadTimer(Common::ThreadCPUTimer::GetForCallingThread());
m_event_loop = new QEventLoop();
m_started_semaphore.release();
if (!VMManager::InitializeMemory())
pxFailRel("Failed to allocate memory map");
// we need input sources ready for binding
reloadInputSources();
createBackgroundControllerPollTimer();
startBackgroundControllerPollTimer();
while (!m_shutdown_flag.load())
{
if (!VMManager::HasValidVM())
{
m_event_loop->exec();
continue;
}
executeVM();
}
stopBackgroundControllerPollTimer();
destroyBackgroundControllerPollTimer();
InputManager::CloseSources();
VMManager::ReleaseMemory();
PerformanceMetrics::SetCPUThreadTimer(Common::ThreadCPUTimer());
moveToThread(m_ui_thread);
deleteLater();
}
void EmuThread::destroyVM()
{
VMManager::Shutdown();
}
void EmuThread::executeVM()
{
for (;;)
{
switch (VMManager::GetState())
{
case VMState::Initializing:
pxFailRel("Shouldn't be in the starting state state");
continue;
case VMState::Paused:
m_event_loop->exec();
continue;
case VMState::Running:
m_event_loop->processEvents(QEventLoop::AllEvents);
VMManager::Execute();
continue;
case VMState::Stopping:
destroyVM();
m_event_loop->processEvents(QEventLoop::AllEvents);
return;
}
}
}
void EmuThread::createBackgroundControllerPollTimer()
{
pxAssert(!m_background_controller_polling_timer);
m_background_controller_polling_timer = new QTimer(this);
m_background_controller_polling_timer->setSingleShot(false);
m_background_controller_polling_timer->setTimerType(Qt::CoarseTimer);
connect(m_background_controller_polling_timer, &QTimer::timeout, this, &EmuThread::doBackgroundControllerPoll);
}
void EmuThread::destroyBackgroundControllerPollTimer()
{
delete m_background_controller_polling_timer;
m_background_controller_polling_timer = nullptr;
}
void EmuThread::startBackgroundControllerPollTimer()
{
if (m_background_controller_polling_timer->isActive())
return;
m_background_controller_polling_timer->start(BACKGROUND_CONTROLLER_POLLING_INTERVAL);
}
void EmuThread::stopBackgroundControllerPollTimer()
{
if (!m_background_controller_polling_timer->isActive())
return;
m_background_controller_polling_timer->stop();
}
void EmuThread::doBackgroundControllerPoll()
{
InputManager::PollSources();
}
void EmuThread::toggleFullscreen()
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, &EmuThread::toggleFullscreen, Qt::QueuedConnection);
return;
}
setFullscreen(!m_is_fullscreen);
}
void EmuThread::setFullscreen(bool fullscreen)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "setFullscreen", Qt::QueuedConnection, Q_ARG(bool, fullscreen));
return;
}
if (!VMManager::HasValidVM() || m_is_fullscreen == fullscreen)
return;
// This will call back to us on the MTGS thread.
m_is_fullscreen = fullscreen;
GetMTGS().UpdateDisplayWindow();
GetMTGS().WaitGS();
}
void EmuThread::applySettings()
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, &EmuThread::applySettings, Qt::QueuedConnection);
return;
}
checkForSettingChanges();
VMManager::ApplySettings();
}
void EmuThread::checkForSettingChanges()
{
if (VMManager::HasValidVM())
{
const bool render_to_main = QtHost::GetBaseBoolSettingValue("UI", "RenderToMainWindow", true);
if (!m_is_fullscreen && m_is_rendering_to_main != render_to_main)
{
m_is_rendering_to_main = render_to_main;
GetMTGS().UpdateDisplayWindow();
GetMTGS().WaitGS();
}
}
}
void EmuThread::toggleSoftwareRendering()
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, &EmuThread::toggleSoftwareRendering, Qt::QueuedConnection);
return;
}
if (!VMManager::HasValidVM())
return;
GetMTGS().ToggleSoftwareRendering();
}
void EmuThread::switchRenderer(GSRendererType renderer)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "switchRenderer", Qt::QueuedConnection, Q_ARG(GSRendererType, renderer));
return;
}
if (!VMManager::HasValidVM())
return;
GetMTGS().SwitchRenderer(renderer);
}
void EmuThread::changeDisc(const QString& path)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "changeDisc", Qt::QueuedConnection, Q_ARG(const QString&, path));
return;
}
if (!VMManager::HasValidVM())
return;
VMManager::ChangeDisc(path.toStdString());
}
void EmuThread::reloadPatches()
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, &EmuThread::reloadPatches, Qt::QueuedConnection);
return;
}
if (!VMManager::HasValidVM())
return;
VMManager::ReloadPatches(true);
}
void EmuThread::reloadInputSources()
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, &EmuThread::reloadInputSources, Qt::QueuedConnection);
return;
}
auto lock = Host::GetSettingsLock();
SettingsInterface* si = Host::GetSettingsInterface();
InputManager::ReloadSources(*si);
// skip loading bindings if we're not running, since it'll get done on startup anyway
if (VMManager::HasValidVM())
InputManager::ReloadBindings(*si);
}
void EmuThread::reloadInputBindings()
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, &EmuThread::reloadInputBindings, Qt::QueuedConnection);
return;
}
// skip loading bindings if we're not running, since it'll get done on startup anyway
if (!VMManager::HasValidVM())
return;
auto lock = Host::GetSettingsLock();
SettingsInterface* si = Host::GetSettingsInterface();
InputManager::ReloadBindings(*si);
}
void EmuThread::requestDisplaySize(float scale)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "requestDisplaySize", Qt::QueuedConnection, Q_ARG(float, scale));
return;
}
if (!VMManager::HasValidVM())
return;
VMManager::RequestDisplaySize(scale);
}
void EmuThread::enumerateInputDevices()
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, &EmuThread::enumerateInputDevices, Qt::QueuedConnection);
return;
}
const std::vector<std::pair<std::string, std::string>> devs(InputManager::EnumerateDevices());
QList<QPair<QString, QString>> qdevs;
qdevs.reserve(devs.size());
for (const std::pair<std::string, std::string>& dev : devs)
qdevs.emplace_back(QString::fromStdString(dev.first), QString::fromStdString(dev.second));
onInputDevicesEnumerated(qdevs);
}
void EmuThread::enumerateVibrationMotors()
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, &EmuThread::enumerateVibrationMotors, Qt::QueuedConnection);
return;
}
const std::vector<InputBindingKey> motors(InputManager::EnumerateMotors());
QList<InputBindingKey> qmotors;
qmotors.reserve(motors.size());
for (InputBindingKey key : motors)
qmotors.push_back(key);
onVibrationMotorsEnumerated(qmotors);
}
void EmuThread::connectDisplaySignals(DisplayWidget* widget)
{
widget->disconnect(this);
connect(widget, &DisplayWidget::windowFocusEvent, this, &EmuThread::onDisplayWindowFocused);
connect(widget, &DisplayWidget::windowResizedEvent, this, &EmuThread::onDisplayWindowResized);
// connect(widget, &DisplayWidget::windowRestoredEvent, this, &EmuThread::redrawDisplayWindow);
connect(widget, &DisplayWidget::windowClosedEvent, []() { g_emu_thread->shutdownVM(true, true); });
connect(widget, &DisplayWidget::windowKeyEvent, this, &EmuThread::onDisplayWindowKeyEvent);
connect(widget, &DisplayWidget::windowMouseMoveEvent, this, &EmuThread::onDisplayWindowMouseMoveEvent);
connect(widget, &DisplayWidget::windowMouseButtonEvent, this, &EmuThread::onDisplayWindowMouseButtonEvent);
connect(widget, &DisplayWidget::windowMouseWheelEvent, this, &EmuThread::onDisplayWindowMouseWheelEvent);
}
void EmuThread::onDisplayWindowMouseMoveEvent(int x, int y) {}
void EmuThread::onDisplayWindowMouseButtonEvent(int button, bool pressed)
{
InputManager::InvokeEvents(InputManager::MakeHostMouseButtonKey(button), pressed ? 1.0f : 0.0f);
}
void EmuThread::onDisplayWindowMouseWheelEvent(const QPoint& delta_angle) {}
void EmuThread::onDisplayWindowKeyEvent(int key, int mods, bool pressed)
{
InputManager::InvokeEvents(InputManager::MakeHostKeyboardKey(key), pressed ? 1.0f : 0.0f);
}
void EmuThread::onDisplayWindowResized(int width, int height, float scale)
{
if (!VMManager::HasValidVM())
return;
GetMTGS().ResizeDisplayWindow(width, height, scale);
}
void EmuThread::onDisplayWindowFocused() {}
void EmuThread::updateDisplay()
{
pxAssertRel(!isOnEmuThread(), "Not on emu thread");
// finished with the display for now
HostDisplay* display = Host::GetHostDisplay();
display->DoneRenderContextCurrent();
// but we should get it back after this call
DisplayWidget* widget = onUpdateDisplayRequested(m_is_fullscreen, !m_is_fullscreen && m_is_rendering_to_main);
if (!widget || !display->MakeRenderContextCurrent())
{
pxFailRel("Failed to recreate context after updating");
return;
}
// this is always a new widget, so reconnect it
connectDisplaySignals(widget);
}
HostDisplay* EmuThread::acquireHostDisplay(HostDisplay::RenderAPI api)
{
s_host_display = HostDisplay::CreateDisplayForAPI(api);
if (!s_host_display)
return nullptr;
DisplayWidget* widget = emit onCreateDisplayRequested(m_is_fullscreen, m_is_rendering_to_main);
if (!widget)
{
s_host_display.reset();
return nullptr;
}
connectDisplaySignals(widget);
if (!s_host_display->MakeRenderContextCurrent())
{
Console.Error("Failed to make render context current");
releaseHostDisplay();
return nullptr;
}
if (!s_host_display->InitializeRenderDevice(StringUtil::wxStringToUTF8String(EmuFolders::Cache.ToString()), false) ||
!ImGuiManager::Initialize())
{
Console.Error("Failed to initialize device/imgui");
releaseHostDisplay();
return nullptr;
}
g_gs_window_info = s_host_display->GetWindowInfo();
return s_host_display.get();
}
void EmuThread::releaseHostDisplay()
{
ImGuiManager::Shutdown();
if (s_host_display)
{
s_host_display->DestroyRenderSurface();
s_host_display->DestroyRenderDevice();
}
g_gs_window_info = WindowInfo();
emit onDestroyDisplayRequested();
s_host_display.reset();
}
HostDisplay* Host::GetHostDisplay()
{
return s_host_display.get();
}
HostDisplay* Host::AcquireHostDisplay(HostDisplay::RenderAPI api)
{
return g_emu_thread->acquireHostDisplay(api);
}
void Host::ReleaseHostDisplay()
{
g_emu_thread->releaseHostDisplay();
}
bool Host::BeginPresentFrame(bool frame_skip)
{
return s_host_display->BeginPresent(frame_skip);
}
void Host::EndPresentFrame()
{
ImGuiManager::RenderOSD();
s_host_display->EndPresent();
ImGuiManager::NewFrame();
}
void Host::ResizeHostDisplay(u32 new_window_width, u32 new_window_height, float new_window_scale)
{
s_host_display->ResizeRenderWindow(new_window_width, new_window_height, new_window_scale);
ImGuiManager::WindowResized();
}
void Host::RequestResizeHostDisplay(s32 width, s32 height)
{
g_emu_thread->onResizeDisplayRequested(width, height);
}
void Host::UpdateHostDisplay()
{
g_emu_thread->updateDisplay();
ImGuiManager::WindowResized();
}
void Host::OnVMStarting()
{
g_emu_thread->stopBackgroundControllerPollTimer();
emit g_emu_thread->onVMStarting();
}
void Host::OnVMStarted()
{
emit g_emu_thread->onVMStarted();
}
void Host::OnVMDestroyed()
{
emit g_emu_thread->onVMStopped();
g_emu_thread->startBackgroundControllerPollTimer();
}
void Host::OnVMPaused()
{
g_emu_thread->startBackgroundControllerPollTimer();
emit g_emu_thread->onVMPaused();
}
void Host::OnVMResumed()
{
// exit the event loop when we eventually return
g_emu_thread->getEventLoop()->quit();
g_emu_thread->stopBackgroundControllerPollTimer();
emit g_emu_thread->onVMResumed();
}
void Host::OnGameChanged(const std::string& disc_path, const std::string& game_serial, const std::string& game_name,
u32 game_crc)
{
emit g_emu_thread->onGameChanged(QString::fromStdString(disc_path), QString::fromStdString(game_serial),
QString::fromStdString(game_name), game_crc);
}
void Host::PumpMessagesOnCPUThread()
{
g_emu_thread->getEventLoop()->processEvents(QEventLoop::AllEvents);
}
ScopedVMPause::ScopedVMPause(bool was_paused)
: m_was_paused(was_paused)
{
if (!m_was_paused)
g_emu_thread->setVMPaused(true);
}
ScopedVMPause::~ScopedVMPause()
{
if (m_was_paused)
g_emu_thread->setVMPaused(false);
}
alignas(16) static SysMtgsThread s_mtgs_thread;
SysMtgsThread& GetMTGS()
{
return s_mtgs_thread;
}
// ------------------------------------------------------------------------
// Hotkeys
// ------------------------------------------------------------------------
BEGIN_HOTKEY_LIST(g_host_hotkeys)
DEFINE_HOTKEY("Screenshot", "General", "Save Screenshot", [](bool pressed) {
if (!pressed)
{
// TODO
}
})
DEFINE_HOTKEY("TogglePause", "System", "Toggle Pause", [](bool pressed) {
if (!pressed)
g_emu_thread->setVMPaused(VMManager::GetState() != VMState::Paused);
})
DEFINE_HOTKEY("ToggleFullscreen", "General", "Toggle Fullscreen", [](bool pressed) {
if (!pressed)
g_emu_thread->toggleFullscreen();
})
END_HOTKEY_LIST()

144
pcsx2-qt/EmuThread.h Normal file
View File

@ -0,0 +1,144 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "pcsx2/Host.h"
#include "pcsx2/HostDisplay.h"
#include "pcsx2/Frontend/InputManager.h"
#include <QtCore/QList>
#include <QtCore/QEventLoop>
#include <QtCore/QPair>
#include <QtCore/QString>
#include <QtCore/QSemaphore>
#include <QtCore/QTimer>
#include <QtCore/QThread>
#include <atomic>
#include <memory>
class DisplayWidget;
struct VMBootParameters;
class EmuThread : public QThread
{
Q_OBJECT
public:
explicit EmuThread(QThread* ui_thread);
~EmuThread();
static void start();
static void stop();
__fi QEventLoop* getEventLoop() const { return m_event_loop; }
bool isOnEmuThread() const;
/// Called back from the GS thread when the display state changes (e.g. fullscreen, render to main).
HostDisplay* acquireHostDisplay(HostDisplay::RenderAPI api);
void releaseHostDisplay();
void updateDisplay();
void startBackgroundControllerPollTimer();
void stopBackgroundControllerPollTimer();
public Q_SLOTS:
void startVM(std::shared_ptr<VMBootParameters> boot_params);
void resetVM();
void setVMPaused(bool paused);
void shutdownVM(bool allow_save_to_state = true, bool blocking = false);
void loadState(const QString& filename);
void loadStateFromSlot(qint32 slot);
void saveState(const QString& filename);
void saveStateToSlot(qint32 slot);
void toggleFullscreen();
void setFullscreen(bool fullscreen);
void applySettings();
void toggleSoftwareRendering();
void switchRenderer(GSRendererType renderer);
void changeDisc(const QString& path);
void reloadPatches();
void reloadInputSources();
void reloadInputBindings();
void requestDisplaySize(float scale);
void enumerateInputDevices();
void enumerateVibrationMotors();
Q_SIGNALS:
DisplayWidget* onCreateDisplayRequested(bool fullscreen, bool render_to_main);
DisplayWidget* onUpdateDisplayRequested(bool fullscreen, bool render_to_main);
void onResizeDisplayRequested(qint32 width, qint32 height);
void onDestroyDisplayRequested();
void onVMStarting();
void onVMStarted();
void onVMPaused();
void onVMResumed();
void onVMStopped();
void onGameChanged(const QString& path, const QString& serial, const QString& name, quint32 crc);
void onInputDevicesEnumerated(const QList<QPair<QString, QString>>& devices);
void onInputDeviceConnected(const QString& identifier, const QString& device_name);
void onInputDeviceDisconnected(const QString& identifier);
void onVibrationMotorsEnumerated(const QList<InputBindingKey>& motors);
protected:
void run();
private:
static constexpr u32 BACKGROUND_CONTROLLER_POLLING_INTERVAL =
100; /// Interval at which the controllers are polled when the system is not active.
void connectDisplaySignals(DisplayWidget* widget);
void destroyVM();
void executeVM();
void checkForSettingChanges();
void createBackgroundControllerPollTimer();
void destroyBackgroundControllerPollTimer();
private Q_SLOTS:
void stopInThread();
void doBackgroundControllerPoll();
void onDisplayWindowMouseMoveEvent(int x, int y);
void onDisplayWindowMouseButtonEvent(int button, bool pressed);
void onDisplayWindowMouseWheelEvent(const QPoint& delta_angle);
void onDisplayWindowResized(int width, int height, float scale);
void onDisplayWindowFocused();
void onDisplayWindowKeyEvent(int key, int mods, bool pressed);
private:
QThread* m_ui_thread;
QSemaphore m_started_semaphore;
QEventLoop* m_event_loop = nullptr;
QTimer* m_background_controller_polling_timer = nullptr;
std::atomic_bool m_shutdown_flag{false};
bool m_is_rendering_to_main = false;
bool m_is_fullscreen = false;
};
/// <summary>
/// Helper class to pause/unpause the emulation thread.
/// </summary>
class ScopedVMPause
{
public:
ScopedVMPause(bool was_paused);
~ScopedVMPause();
private:
bool m_was_paused;
};
extern EmuThread* g_emu_thread;

View File

@ -0,0 +1,490 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "GameListModel.h"
#include "common/FileSystem.h"
#include "common/StringUtil.h"
#include <QtCore/QDate>
#include <QtCore/QDateTime>
#include <QtGui/QGuiApplication>
#include <QtGui/QIcon>
#include <QtGui/QPainter>
static constexpr std::array<const char*, GameListModel::Column_Count> s_column_names = {
{"Type", "Code", "Title", "File Title", "CRC", "Size", "Region", "Compatibility", "Cover"}};
static constexpr int COVER_ART_WIDTH = 350;
static constexpr int COVER_ART_HEIGHT = 512;
static constexpr int COVER_ART_SPACING = 32;
static int DPRScale(int size, float dpr)
{
return static_cast<int>(static_cast<float>(size) * dpr);
}
static int DPRUnscale(int size, float dpr)
{
return static_cast<int>(static_cast<float>(size) / dpr);
}
static void resizeAndPadPixmap(QPixmap* pm, int expected_width, int expected_height, float dpr)
{
const int dpr_expected_width = DPRScale(expected_width, dpr);
const int dpr_expected_height = DPRScale(expected_height, dpr);
if (pm->width() == dpr_expected_width && pm->height() == dpr_expected_height)
return;
*pm = pm->scaled(dpr_expected_width, dpr_expected_height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
if (pm->width() == dpr_expected_width && pm->height() == dpr_expected_height)
return;
// QPainter works in unscaled coordinates.
int xoffs = 0;
int yoffs = 0;
if (pm->width() < dpr_expected_width)
xoffs = DPRUnscale((dpr_expected_width - pm->width()) / 2, dpr);
if (pm->height() < dpr_expected_height)
yoffs = DPRUnscale((dpr_expected_height - pm->height()) / 2, dpr);
QPixmap padded_image(dpr_expected_width, dpr_expected_height);
padded_image.setDevicePixelRatio(dpr);
padded_image.fill(Qt::transparent);
QPainter painter;
if (painter.begin(&padded_image))
{
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.drawPixmap(xoffs, yoffs, *pm);
painter.setCompositionMode(QPainter::CompositionMode_Destination);
painter.fillRect(padded_image.rect(), QColor(0, 0, 0, 0));
painter.end();
}
*pm = padded_image;
}
static QPixmap createPlaceholderImage(const QPixmap& placeholder_pixmap, int width, int height, float scale,
const std::string& title)
{
const float dpr = qApp->devicePixelRatio();
QPixmap pm(placeholder_pixmap.copy());
pm.setDevicePixelRatio(dpr);
if (pm.isNull())
return QPixmap();
resizeAndPadPixmap(&pm, width, height, dpr);
QPainter painter;
if (painter.begin(&pm))
{
QFont font;
font.setPointSize(std::max(static_cast<int>(32.0f * scale), 1));
painter.setFont(font);
painter.setPen(Qt::white);
const QRect text_rc(0, 0, static_cast<int>(static_cast<float>(width)),
static_cast<int>(static_cast<float>(height)));
painter.drawText(text_rc, Qt::AlignCenter | Qt::TextWordWrap, QString::fromStdString(title));
painter.end();
}
return pm;
}
std::optional<GameListModel::Column> GameListModel::getColumnIdForName(std::string_view name)
{
for (int column = 0; column < Column_Count; column++)
{
if (name == s_column_names[column])
return static_cast<Column>(column);
}
return std::nullopt;
}
const char* GameListModel::getColumnName(Column col)
{
return s_column_names[static_cast<int>(col)];
}
GameListModel::GameListModel(QObject* parent /* = nullptr */)
: QAbstractTableModel(parent)
{
loadCommonImages();
setColumnDisplayNames();
}
GameListModel::~GameListModel() = default;
void GameListModel::setCoverScale(float scale)
{
if (m_cover_scale == scale)
return;
m_cover_pixmap_cache.clear();
m_cover_scale = scale;
}
void GameListModel::refreshCovers()
{
m_cover_pixmap_cache.clear();
refresh();
}
int GameListModel::getCoverArtWidth() const
{
return std::max(static_cast<int>(static_cast<float>(COVER_ART_WIDTH) * m_cover_scale), 1);
}
int GameListModel::getCoverArtHeight() const
{
return std::max(static_cast<int>(static_cast<float>(COVER_ART_HEIGHT) * m_cover_scale), 1);
}
int GameListModel::getCoverArtSpacing() const
{
return std::max(static_cast<int>(static_cast<float>(COVER_ART_SPACING) * m_cover_scale), 1);
}
int GameListModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid())
return 0;
return static_cast<int>(GameList::GetEntryCount());
}
int GameListModel::columnCount(const QModelIndex& parent) const
{
if (parent.isValid())
return 0;
return Column_Count;
}
QVariant GameListModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid())
return {};
const int row = index.row();
if (row < 0 || row >= static_cast<int>(GameList::GetEntryCount()))
return {};
const auto lock = GameList::GetLock();
const GameList::Entry* ge = GameList::GetEntryByIndex(row);
if (!ge)
return {};
switch (role)
{
case Qt::DisplayRole:
{
switch (index.column())
{
case Column_Serial:
return QString::fromStdString(ge->serial);
case Column_Title:
return QString::fromStdString(ge->title);
case Column_FileTitle:
{
const std::string_view file_title(FileSystem::GetFileTitleFromPath(ge->path));
return QString::fromUtf8(file_title.data(), static_cast<int>(file_title.length()));
}
case Column_CRC:
return QStringLiteral("%1").arg(ge->crc, 8, 16, QChar('0'));
case Column_Size:
return QString("%1 MB").arg(static_cast<double>(ge->total_size) / 1048576.0, 0, 'f', 2);
case Column_Cover:
{
if (m_show_titles_for_covers)
return QString::fromStdString(ge->title);
else
return {};
}
default:
return {};
}
}
case Qt::InitialSortOrderRole:
{
switch (index.column())
{
case Column_Type:
return static_cast<int>(ge->type);
case Column_Serial:
return QString::fromStdString(ge->serial);
case Column_Title:
case Column_Cover:
return QString::fromStdString(ge->title);
case Column_FileTitle:
{
const std::string_view file_title(FileSystem::GetFileTitleFromPath(ge->path));
return QString::fromUtf8(file_title.data(), static_cast<int>(file_title.length()));
}
case Column_CRC:
return static_cast<int>(ge->crc);
case Column_Region:
return static_cast<int>(ge->region);
case Column_Compatibility:
return static_cast<int>(ge->compatibility_rating);
case Column_Size:
return static_cast<qulonglong>(ge->total_size);
default:
return {};
}
}
case Qt::DecorationRole:
{
switch (index.column())
{
case Column_Type:
{
switch (ge->type)
{
case GameList::EntryType::PS1Disc:
case GameList::EntryType::PS2Disc:
// return ((ge->settings.GetUserSettingsCount() > 0) ? m_type_disc_with_settings_pixmap : // m_type_disc_pixmap);
return m_type_disc_pixmap;
case GameList::EntryType::Playlist:
return m_type_playlist_pixmap;
case GameList::EntryType::ELF:
default:
return m_type_exe_pixmap;
}
}
case Column_Region:
{
switch (ge->region)
{
case GameList::Region::NTSC_J:
return m_region_jp_pixmap;
case GameList::Region::NTSC_UC:
return m_region_us_pixmap;
case GameList::Region::PAL:
return m_region_eu_pixmap;
case GameList::Region::Other:
default:
return m_region_other_pixmap;
}
}
case Column_Compatibility:
{
return m_compatibiliy_pixmaps[static_cast<int>(
(static_cast<u32>(ge->compatibility_rating) >= GameList::CompatibilityRatingCount) ?
GameList::CompatibilityRating::Unknown :
ge->compatibility_rating)];
}
case Column_Cover:
{
auto it = m_cover_pixmap_cache.find(ge->path);
if (it != m_cover_pixmap_cache.end())
return it->second;
QPixmap image;
std::string path = GameList::GetCoverImagePathForEntry(ge);
if (!path.empty())
{
const float dpr = qApp->devicePixelRatio();
image = QPixmap(QString::fromStdString(path));
if (!image.isNull())
{
image.setDevicePixelRatio(dpr);
resizeAndPadPixmap(&image, getCoverArtWidth(), getCoverArtHeight(), dpr);
}
}
if (image.isNull())
{
image = createPlaceholderImage(m_placeholder_pixmap, getCoverArtWidth(), getCoverArtHeight(), m_cover_scale,
ge->title);
}
m_cover_pixmap_cache.emplace(ge->path, image);
return image;
}
break;
default:
return {};
}
default:
return {};
}
}
}
QVariant GameListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation != Qt::Horizontal || role != Qt::DisplayRole || section < 0 || section >= Column_Count)
return {};
return m_column_display_names[section];
}
void GameListModel::refresh()
{
beginResetModel();
endResetModel();
}
bool GameListModel::titlesLessThan(int left_row, int right_row) const
{
if (left_row < 0 || left_row >= static_cast<int>(GameList::GetEntryCount()) || right_row < 0 ||
right_row >= static_cast<int>(GameList::GetEntryCount()))
{
return false;
}
const GameList::Entry* left = GameList::GetEntryByIndex(left_row);
const GameList::Entry* right = GameList::GetEntryByIndex(right_row);
return (StringUtil::Strcasecmp(left->title.c_str(), right->title.c_str()) < 0);
}
bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& right_index, int column) const
{
if (!left_index.isValid() || !right_index.isValid())
return false;
const int left_row = left_index.row();
const int right_row = right_index.row();
if (left_row < 0 || left_row >= static_cast<int>(GameList::GetEntryCount()) || right_row < 0 ||
right_row >= static_cast<int>(GameList::GetEntryCount()))
{
return false;
}
const auto lock = GameList::GetLock();
const GameList::Entry* left = GameList::GetEntryByIndex(left_row);
const GameList::Entry* right = GameList::GetEntryByIndex(right_row);
if (!left || !right)
return false;
switch (column)
{
case Column_Type:
{
if (left->type == right->type)
return titlesLessThan(left_row, right_row);
return static_cast<int>(left->type) < static_cast<int>(right->type);
}
case Column_Serial:
{
if (left->serial == right->serial)
return titlesLessThan(left_row, right_row);
return (StringUtil::Strcasecmp(left->serial.c_str(), right->serial.c_str()) < 0);
}
case Column_Title:
{
return titlesLessThan(left_row, right_row);
}
case Column_FileTitle:
{
const std::string_view file_title_left(FileSystem::GetFileTitleFromPath(left->path));
const std::string_view file_title_right(FileSystem::GetFileTitleFromPath(right->path));
if (file_title_left == file_title_right)
return titlesLessThan(left_row, right_row);
const std::size_t smallest = std::min(file_title_left.size(), file_title_right.size());
return (StringUtil::Strncasecmp(file_title_left.data(), file_title_right.data(), smallest) < 0);
}
case Column_Region:
{
if (left->region == right->region)
return titlesLessThan(left_row, right_row);
return (static_cast<int>(left->region) < static_cast<int>(right->region));
}
case Column_Compatibility:
{
if (left->compatibility_rating == right->compatibility_rating)
return titlesLessThan(left_row, right_row);
return (static_cast<int>(left->compatibility_rating) < static_cast<int>(right->compatibility_rating));
}
case Column_Size:
{
if (left->total_size == right->total_size)
return titlesLessThan(left_row, right_row);
return (left->total_size < right->total_size);
}
case Column_CRC:
{
if (left->crc == right->crc)
return titlesLessThan(left_row, right_row);
return (left->crc < right->crc);
}
default:
return false;
}
}
void GameListModel::loadCommonImages()
{
m_type_disc_pixmap = QIcon(QStringLiteral(":/icons/media-optical-24.png")).pixmap(QSize(24, 24));
m_type_disc_with_settings_pixmap = QIcon(QStringLiteral(":/icons/media-optical-gear-24.png")).pixmap(QSize(24, 24));
m_type_exe_pixmap = QIcon(QStringLiteral(":/icons/applications-system-24.png")).pixmap(QSize(24, 24));
m_type_playlist_pixmap = QIcon(QStringLiteral(":/icons/address-book-new-22.png")).pixmap(QSize(22, 22));
m_region_eu_pixmap = QIcon(QStringLiteral(":/icons/flag-eu.png")).pixmap(QSize(42, 30));
m_region_jp_pixmap = QIcon(QStringLiteral(":/icons/flag-jp.png")).pixmap(QSize(42, 30));
m_region_us_pixmap = QIcon(QStringLiteral(":/icons/flag-us.png")).pixmap(QSize(42, 30));
m_region_other_pixmap = QIcon(QStringLiteral(":/icons/flag-other.png")).pixmap(QSize(42, 30));
for (u32 i = 1; i < GameList::CompatibilityRatingCount; i++)
m_compatibiliy_pixmaps[i].load(QStringLiteral(":/icons/star-%1.png").arg(i - 1));
m_placeholder_pixmap.load(QString::fromStdString(Path::CombineStdString(EmuFolders::Resources, "cover-placeholder.png")));
}
void GameListModel::setColumnDisplayNames()
{
m_column_display_names[Column_Type] = tr("Type");
m_column_display_names[Column_Serial] = tr("Code");
m_column_display_names[Column_Title] = tr("Title");
m_column_display_names[Column_FileTitle] = tr("File Title");
m_column_display_names[Column_CRC] = tr("CRC");
m_column_display_names[Column_Size] = tr("Size");
m_column_display_names[Column_Region] = tr("Region");
m_column_display_names[Column_Compatibility] = tr("Compatibility");
}

View File

@ -0,0 +1,97 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "pcsx2/Frontend/GameList.h"
#include <QtCore/QAbstractTableModel>
#include <QtGui/QPixmap>
#include <algorithm>
#include <array>
#include <optional>
#include <unordered_map>
class GameListModel final : public QAbstractTableModel
{
Q_OBJECT
public:
enum Column : int
{
Column_Type,
Column_Serial,
Column_Title,
Column_FileTitle,
Column_CRC,
Column_Size,
Column_Region,
Column_Compatibility,
Column_Cover,
Column_Count
};
static std::optional<Column> getColumnIdForName(std::string_view name);
static const char* getColumnName(Column col);
GameListModel(QObject* parent = nullptr);
~GameListModel();
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
__fi const QString& getColumnDisplayName(int column) { return m_column_display_names[column]; }
void refresh();
bool titlesLessThan(int left_row, int right_row) const;
bool lessThan(const QModelIndex& left_index, const QModelIndex& right_index, int column) const;
bool getShowCoverTitles() const { return m_show_titles_for_covers; }
void setShowCoverTitles(bool enabled) { m_show_titles_for_covers = enabled; }
float getCoverScale() const { return m_cover_scale; }
void setCoverScale(float scale);
int getCoverArtWidth() const;
int getCoverArtHeight() const;
int getCoverArtSpacing() const;
void refreshCovers();
private:
void loadCommonImages();
void setColumnDisplayNames();
float m_cover_scale = 1.0f;
bool m_show_titles_for_covers = false;
std::array<QString, Column_Count> m_column_display_names;
QPixmap m_type_disc_pixmap;
QPixmap m_type_disc_with_settings_pixmap;
QPixmap m_type_exe_pixmap;
QPixmap m_type_playlist_pixmap;
QPixmap m_region_jp_pixmap;
QPixmap m_region_eu_pixmap;
QPixmap m_region_us_pixmap;
QPixmap m_region_other_pixmap;
QPixmap m_placeholder_pixmap;
std::array<QPixmap, static_cast<int>(GameList::CompatibilityRatingCount)> m_compatibiliy_pixmaps;
mutable std::unordered_map<std::string, QPixmap> m_cover_pixmap_cache;
};

View File

@ -0,0 +1,130 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "common/ProgressCallback.h"
#include "common/Timer.h"
#include "pcsx2/Frontend/GameList.h"
#include "GameListRefreshThread.h"
#include <QtWidgets/QMessageBox>
// Limit UI update times to 4 per second, so we don't spend longer redrawing the UI than scanning
static constexpr float UI_UPDATE_INTERVAL = 0.25f;
AsyncRefreshProgressCallback::AsyncRefreshProgressCallback(GameListRefreshThread* parent)
: m_parent(parent)
{
}
void AsyncRefreshProgressCallback::Cancel()
{
// Not atomic, but we don't need to cancel immediately.
m_cancelled = true;
}
void AsyncRefreshProgressCallback::SetStatusText(const char* text)
{
QString new_text(QString::fromUtf8(text));
if (new_text == m_status_text)
return;
m_status_text = new_text;
fireUpdate();
}
void AsyncRefreshProgressCallback::SetProgressRange(u32 range)
{
BaseProgressCallback::SetProgressRange(range);
if (static_cast<int>(m_progress_range) == m_last_range)
return;
m_last_range = static_cast<int>(m_progress_range);
fireUpdate();
}
void AsyncRefreshProgressCallback::SetProgressValue(u32 value)
{
BaseProgressCallback::SetProgressValue(value);
if (static_cast<int>(m_progress_value) == m_last_value)
return;
m_last_value = static_cast<int>(m_progress_value);
fireUpdate();
}
void AsyncRefreshProgressCallback::SetTitle(const char* title) {}
void AsyncRefreshProgressCallback::DisplayError(const char* message)
{
QMessageBox::critical(nullptr, QStringLiteral("Error"), QString::fromUtf8(message));
}
void AsyncRefreshProgressCallback::DisplayWarning(const char* message)
{
QMessageBox::warning(nullptr, QStringLiteral("Warning"), QString::fromUtf8(message));
}
void AsyncRefreshProgressCallback::DisplayInformation(const char* message)
{
QMessageBox::information(nullptr, QStringLiteral("Information"), QString::fromUtf8(message));
}
void AsyncRefreshProgressCallback::DisplayDebugMessage(const char* message)
{
qDebug() << message;
}
void AsyncRefreshProgressCallback::ModalError(const char* message)
{
QMessageBox::critical(nullptr, QStringLiteral("Error"), QString::fromUtf8(message));
}
bool AsyncRefreshProgressCallback::ModalConfirmation(const char* message)
{
return QMessageBox::question(nullptr, QStringLiteral("Question"), QString::fromUtf8(message)) == QMessageBox::Yes;
}
void AsyncRefreshProgressCallback::ModalInformation(const char* message)
{
QMessageBox::information(nullptr, QStringLiteral("Information"), QString::fromUtf8(message));
}
void AsyncRefreshProgressCallback::fireUpdate()
{
m_parent->refreshProgress(m_status_text, m_last_value, m_last_range);
}
GameListRefreshThread::GameListRefreshThread(bool invalidate_cache)
: QThread()
, m_progress(this)
, m_invalidate_cache(invalidate_cache)
{
}
GameListRefreshThread::~GameListRefreshThread() = default;
void GameListRefreshThread::cancel()
{
m_progress.Cancel();
}
void GameListRefreshThread::run()
{
GameList::Refresh(m_invalidate_cache, &m_progress);
emit refreshComplete();
}

View File

@ -0,0 +1,75 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtCore/QThread>
#include <QtCore/QSemaphore>
#include "common/ProgressCallback.h"
#include "common/Timer.h"
class GameListRefreshThread;
class AsyncRefreshProgressCallback : public BaseProgressCallback
{
public:
AsyncRefreshProgressCallback(GameListRefreshThread* parent);
void Cancel();
void SetStatusText(const char* text) override;
void SetProgressRange(u32 range) override;
void SetProgressValue(u32 value) override;
void SetTitle(const char* title) override;
void DisplayError(const char* message) override;
void DisplayWarning(const char* message) override;
void DisplayInformation(const char* message) override;
void DisplayDebugMessage(const char* message) override;
void ModalError(const char* message) override;
bool ModalConfirmation(const char* message) override;
void ModalInformation(const char* message) override;
private:
void fireUpdate();
GameListRefreshThread* m_parent;
Common::Timer m_last_update_time;
QString m_status_text;
int m_last_range = 1;
int m_last_value = 0;
};
class GameListRefreshThread final : public QThread
{
Q_OBJECT
public:
GameListRefreshThread(bool invalidate_cache);
~GameListRefreshThread();
void cancel();
Q_SIGNALS:
void refreshProgress(const QString& status, int current, int total);
void refreshComplete();
protected:
void run();
private:
AsyncRefreshProgressCallback m_progress;
bool m_invalidate_cache;
};

View File

@ -0,0 +1,457 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "common/StringUtil.h"
#include "pcsx2/Frontend/GameList.h"
#include <QtCore/QSortFilterProxyModel>
#include <QtGui/QPixmap>
#include <QtGui/QWheelEvent>
#include <QtWidgets/QApplication>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMenu>
#include "GameListModel.h"
#include "GameListRefreshThread.h"
#include "GameListWidget.h"
#include "QtHost.h"
#include "QtUtils.h"
class GameListSortModel final : public QSortFilterProxyModel
{
public:
explicit GameListSortModel(GameListModel* parent)
: QSortFilterProxyModel(parent)
, m_model(parent)
{
}
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override
{
// TODO: Search
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override
{
return m_model->lessThan(source_left, source_right, source_left.column());
}
private:
GameListModel* m_model;
};
GameListWidget::GameListWidget(QWidget* parent /* = nullptr */)
: QStackedWidget(parent)
{
}
GameListWidget::~GameListWidget() = default;
void GameListWidget::initialize()
{
m_model = new GameListModel(this);
m_model->setCoverScale(QtHost::GetBaseFloatSettingValue("UI", "GameListCoverArtScale", 0.45f));
m_model->setShowCoverTitles(QtHost::GetBaseBoolSettingValue("UI", "GameListShowCoverTitles", true));
m_model->setCoverScale(0.45f);
m_model->setShowCoverTitles(true);
m_sort_model = new GameListSortModel(m_model);
m_sort_model->setSourceModel(m_model);
m_table_view = new QTableView(this);
m_table_view->setModel(m_sort_model);
m_table_view->setSortingEnabled(true);
m_table_view->setSelectionMode(QAbstractItemView::SingleSelection);
m_table_view->setSelectionBehavior(QAbstractItemView::SelectRows);
m_table_view->setContextMenuPolicy(Qt::CustomContextMenu);
m_table_view->setAlternatingRowColors(true);
m_table_view->setShowGrid(false);
m_table_view->setCurrentIndex({});
m_table_view->horizontalHeader()->setHighlightSections(false);
m_table_view->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
m_table_view->verticalHeader()->hide();
m_table_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
loadTableViewColumnVisibilitySettings();
loadTableViewColumnSortSettings();
connect(m_table_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
&GameListWidget::onSelectionModelCurrentChanged);
connect(m_table_view, &QTableView::activated, this, &GameListWidget::onTableViewItemActivated);
connect(m_table_view, &QTableView::customContextMenuRequested, this,
&GameListWidget::onTableViewContextMenuRequested);
connect(m_table_view->horizontalHeader(), &QHeaderView::customContextMenuRequested, this,
&GameListWidget::onTableViewHeaderContextMenuRequested);
connect(m_table_view->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this,
&GameListWidget::onTableViewHeaderSortIndicatorChanged);
insertWidget(0, m_table_view);
m_list_view = new GameListGridListView(this);
m_list_view->setModel(m_sort_model);
m_list_view->setModelColumn(GameListModel::Column_Cover);
m_list_view->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_list_view->setViewMode(QListView::IconMode);
m_list_view->setResizeMode(QListView::Adjust);
m_list_view->setUniformItemSizes(true);
m_list_view->setItemAlignment(Qt::AlignHCenter);
m_list_view->setContextMenuPolicy(Qt::CustomContextMenu);
m_list_view->setFrameStyle(QFrame::NoFrame);
m_list_view->setSpacing(m_model->getCoverArtSpacing());
updateListFont();
connect(m_list_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
&GameListWidget::onSelectionModelCurrentChanged);
connect(m_list_view, &GameListGridListView::zoomIn, this, &GameListWidget::gridZoomIn);
connect(m_list_view, &GameListGridListView::zoomOut, this, &GameListWidget::gridZoomOut);
connect(m_list_view, &QListView::activated, this, &GameListWidget::onListViewItemActivated);
connect(m_list_view, &QListView::customContextMenuRequested, this, &GameListWidget::onListViewContextMenuRequested);
insertWidget(1, m_list_view);
if (QtHost::GetBaseBoolSettingValue("UI", "GameListGridView", false))
setCurrentIndex(1);
else
setCurrentIndex(0);
resizeTableViewColumnsToFit();
}
bool GameListWidget::isShowingGameList() const
{
return currentIndex() == 0;
}
bool GameListWidget::isShowingGameGrid() const
{
return currentIndex() == 1;
}
bool GameListWidget::getShowGridCoverTitles() const
{
return m_model->getShowCoverTitles();
}
void GameListWidget::refresh(bool invalidate_cache)
{
if (m_refresh_thread)
{
m_refresh_thread->cancel();
m_refresh_thread->wait();
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
pxAssertRel(!m_refresh_thread, "Game list thread should be unreferenced by now");
}
m_refresh_thread = new GameListRefreshThread(invalidate_cache);
connect(m_refresh_thread, &GameListRefreshThread::refreshProgress, this, &GameListWidget::onRefreshProgress,
Qt::QueuedConnection);
connect(m_refresh_thread, &GameListRefreshThread::refreshComplete, this, &GameListWidget::onRefreshComplete,
Qt::QueuedConnection);
m_refresh_thread->start();
}
void GameListWidget::onRefreshProgress(const QString& status, int current, int total)
{
m_model->refresh();
emit refreshProgress(status, current, total);
}
void GameListWidget::onRefreshComplete()
{
m_model->refresh();
emit refreshComplete();
pxAssertRel(m_refresh_thread, "Has a refresh thread");
m_refresh_thread->wait();
delete m_refresh_thread;
m_refresh_thread = nullptr;
}
void GameListWidget::onSelectionModelCurrentChanged(const QModelIndex& current, const QModelIndex& previous)
{
const QModelIndex source_index = m_sort_model->mapToSource(current);
if (!source_index.isValid() || source_index.row() >= static_cast<int>(GameList::GetEntryCount()))
return;
emit selectionChanged();
}
void GameListWidget::onTableViewItemActivated(const QModelIndex& index)
{
const QModelIndex source_index = m_sort_model->mapToSource(index);
if (!source_index.isValid() || source_index.row() >= static_cast<int>(GameList::GetEntryCount()))
return;
emit entryActivated();
}
void GameListWidget::onTableViewContextMenuRequested(const QPoint& point)
{
emit entryContextMenuRequested(m_table_view->mapToGlobal(point));
}
void GameListWidget::onListViewItemActivated(const QModelIndex& index)
{
const QModelIndex source_index = m_sort_model->mapToSource(index);
if (!source_index.isValid() || source_index.row() >= static_cast<int>(GameList::GetEntryCount()))
return;
emit entryActivated();
}
void GameListWidget::onListViewContextMenuRequested(const QPoint& point)
{
emit entryContextMenuRequested(m_list_view->mapToGlobal(point));
}
void GameListWidget::onTableViewHeaderContextMenuRequested(const QPoint& point)
{
QMenu menu;
for (int column = 0; column < GameListModel::Column_Count; column++)
{
if (column == GameListModel::Column_Cover)
continue;
QAction* action = menu.addAction(m_model->getColumnDisplayName(column));
action->setCheckable(true);
action->setChecked(!m_table_view->isColumnHidden(column));
connect(action, &QAction::toggled, [this, column](bool enabled) {
m_table_view->setColumnHidden(column, !enabled);
saveTableViewColumnVisibilitySettings(column);
resizeTableViewColumnsToFit();
});
}
menu.exec(m_table_view->mapToGlobal(point));
}
void GameListWidget::onTableViewHeaderSortIndicatorChanged(int, Qt::SortOrder)
{
saveTableViewColumnSortSettings();
}
void GameListWidget::listZoom(float delta)
{
static constexpr float MIN_SCALE = 0.1f;
static constexpr float MAX_SCALE = 2.0f;
const float new_scale = std::clamp(m_model->getCoverScale() + delta, MIN_SCALE, MAX_SCALE);
QtHost::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
m_model->setCoverScale(new_scale);
updateListFont();
m_model->refresh();
}
void GameListWidget::gridZoomIn()
{
listZoom(0.05f);
}
void GameListWidget::gridZoomOut()
{
listZoom(-0.05f);
}
void GameListWidget::refreshGridCovers()
{
m_model->refreshCovers();
}
void GameListWidget::showGameList()
{
if (currentIndex() == 0)
return;
QtHost::SetBaseBoolSettingValue("UI", "GameListGridView", false);
setCurrentIndex(0);
resizeTableViewColumnsToFit();
}
void GameListWidget::showGameGrid()
{
if (currentIndex() == 1)
return;
QtHost::SetBaseBoolSettingValue("UI", "GameListGridView", true);
setCurrentIndex(1);
}
void GameListWidget::setShowCoverTitles(bool enabled)
{
if (m_model->getShowCoverTitles() == enabled)
return;
QtHost::SetBaseBoolSettingValue("UI", "GameListShowCoverTitles", enabled);
m_model->setShowCoverTitles(enabled);
if (isShowingGameGrid())
m_model->refresh();
}
void GameListWidget::updateListFont()
{
QFont font;
font.setPointSizeF(16.0f * m_model->getCoverScale());
m_list_view->setFont(font);
}
void GameListWidget::resizeEvent(QResizeEvent* event)
{
QStackedWidget::resizeEvent(event);
resizeTableViewColumnsToFit();
}
void GameListWidget::resizeTableViewColumnsToFit()
{
QtUtils::ResizeColumnsForTableView(m_table_view, {
32, // type
80, // code
-1, // title
-1, // file title
50, // crc
80, // size
50, // region
100 // compatibility
});
}
static std::string getColumnVisibilitySettingsKeyName(int column)
{
return StringUtil::StdStringFromFormat("Show%s",
GameListModel::getColumnName(static_cast<GameListModel::Column>(column)));
}
void GameListWidget::loadTableViewColumnVisibilitySettings()
{
static constexpr std::array<bool, GameListModel::Column_Count> DEFAULT_VISIBILITY = {{
true, // type
true, // code
true, // title
false, // file title
false, // crc
true, // size
true, // region
true // compatibility
}};
for (int column = 0; column < GameListModel::Column_Count; column++)
{
const bool visible = QtHost::GetBaseBoolSettingValue(
"GameListTableView", getColumnVisibilitySettingsKeyName(column).c_str(), DEFAULT_VISIBILITY[column]);
m_table_view->setColumnHidden(column, !visible);
}
}
void GameListWidget::saveTableViewColumnVisibilitySettings()
{
for (int column = 0; column < GameListModel::Column_Count; column++)
{
const bool visible = !m_table_view->isColumnHidden(column);
QtHost::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column).c_str(), visible);
}
}
void GameListWidget::saveTableViewColumnVisibilitySettings(int column)
{
const bool visible = !m_table_view->isColumnHidden(column);
QtHost::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column).c_str(), visible);
}
void GameListWidget::loadTableViewColumnSortSettings()
{
const GameListModel::Column DEFAULT_SORT_COLUMN = GameListModel::Column_Type;
const bool DEFAULT_SORT_DESCENDING = false;
const GameListModel::Column sort_column =
GameListModel::getColumnIdForName(QtHost::GetBaseStringSettingValue("GameListTableView", "SortColumn"))
.value_or(DEFAULT_SORT_COLUMN);
const bool sort_descending =
QtHost::GetBaseBoolSettingValue("GameListTableView", "SortDescending", DEFAULT_SORT_DESCENDING);
m_table_view->sortByColumn(sort_column, sort_descending ? Qt::DescendingOrder : Qt::AscendingOrder);
}
void GameListWidget::saveTableViewColumnSortSettings()
{
const int sort_column = m_table_view->horizontalHeader()->sortIndicatorSection();
const bool sort_descending = (m_table_view->horizontalHeader()->sortIndicatorOrder() == Qt::DescendingOrder);
if (sort_column >= 0 && sort_column < GameListModel::Column_Count)
{
QtHost::SetBaseStringSettingValue(
"GameListTableView", "SortColumn", GameListModel::getColumnName(static_cast<GameListModel::Column>(sort_column)));
}
QtHost::SetBaseBoolSettingValue("GameListTableView", "SortDescending", sort_descending);
}
const GameList::Entry* GameListWidget::getSelectedEntry() const
{
if (currentIndex() == 0)
{
const QItemSelectionModel* selection_model = m_table_view->selectionModel();
if (!selection_model->hasSelection())
return nullptr;
const QModelIndexList selected_rows = selection_model->selectedRows();
if (selected_rows.empty())
return nullptr;
const QModelIndex source_index = m_sort_model->mapToSource(selected_rows[0]);
if (!source_index.isValid())
return nullptr;
return GameList::GetEntryByIndex(source_index.row());
}
else
{
const QItemSelectionModel* selection_model = m_list_view->selectionModel();
if (!selection_model->hasSelection())
return nullptr;
const QModelIndex source_index = m_sort_model->mapToSource(selection_model->currentIndex());
if (!source_index.isValid())
return nullptr;
return GameList::GetEntryByIndex(source_index.row());
}
}
GameListGridListView::GameListGridListView(QWidget* parent /*= nullptr*/)
: QListView(parent)
{
}
void GameListGridListView::wheelEvent(QWheelEvent* e)
{
if (e->modifiers() & Qt::ControlModifier)
{
int dy = e->angleDelta().y();
if (dy != 0)
{
if (dy < 0)
zoomOut();
else
zoomIn();
return;
}
}
QListView::wheelEvent(e);
}

View File

@ -0,0 +1,111 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "pcsx2/Frontend/GameList.h"
#include <QtWidgets/QListView>
#include <QtWidgets/QStackedWidget>
#include <QtWidgets/QTableView>
Q_DECLARE_METATYPE(const GameList::Entry*);
class GameListModel;
class GameListSortModel;
class GameListRefreshThread;
class GameListGridListView : public QListView
{
Q_OBJECT
public:
GameListGridListView(QWidget* parent = nullptr);
Q_SIGNALS:
void zoomOut();
void zoomIn();
protected:
void wheelEvent(QWheelEvent* e);
};
class GameListWidget : public QStackedWidget
{
Q_OBJECT
public:
GameListWidget(QWidget* parent = nullptr);
~GameListWidget();
__fi GameListModel* getModel() const { return m_model; }
void initialize();
void refresh(bool invalidate_cache);
bool isShowingGameList() const;
bool isShowingGameGrid() const;
bool getShowGridCoverTitles() const;
const GameList::Entry* getSelectedEntry() const;
Q_SIGNALS:
void refreshProgress(const QString& status, int current, int total);
void refreshComplete();
void selectionChanged();
void entryActivated();
void entryContextMenuRequested(const QPoint& point);
private Q_SLOTS:
void onRefreshProgress(const QString& status, int current, int total);
void onRefreshComplete();
void onSelectionModelCurrentChanged(const QModelIndex& current, const QModelIndex& previous);
void onTableViewItemActivated(const QModelIndex& index);
void onTableViewContextMenuRequested(const QPoint& point);
void onTableViewHeaderContextMenuRequested(const QPoint& point);
void onTableViewHeaderSortIndicatorChanged(int, Qt::SortOrder);
void onListViewItemActivated(const QModelIndex& index);
void onListViewContextMenuRequested(const QPoint& point);
public Q_SLOTS:
void showGameList();
void showGameGrid();
void setShowCoverTitles(bool enabled);
void gridZoomIn();
void gridZoomOut();
void refreshGridCovers();
protected:
void resizeEvent(QResizeEvent* event);
private:
void resizeTableViewColumnsToFit();
void loadTableViewColumnVisibilitySettings();
void saveTableViewColumnVisibilitySettings();
void saveTableViewColumnVisibilitySettings(int column);
void loadTableViewColumnSortSettings();
void saveTableViewColumnSortSettings();
void listZoom(float delta);
void updateListFont();
GameListModel* m_model = nullptr;
GameListSortModel* m_sort_model = nullptr;
QTableView* m_table_view = nullptr;
GameListGridListView* m_list_view = nullptr;
GameListRefreshThread* m_refresh_thread = nullptr;
};

264
pcsx2-qt/Main.cpp Normal file
View File

@ -0,0 +1,264 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include <QtWidgets/QApplication>
#include <cstdlib>
#include "MainWindow.h"
#include "EmuThread.h"
#include "QtHost.h"
#include "CDVD/CDVD.h"
#include "Frontend/GameList.h"
#include "svnrev.h"
static void PrintCommandLineVersion()
{
std::fprintf(stderr, "PCSX2 Version %s\n", GIT_REV);
std::fprintf(stderr, "https://pcsx2.net/\n");
std::fprintf(stderr, "\n");
}
static void PrintCommandLineHelp(const char* progname)
{
PrintCommandLineVersion();
std::fprintf(stderr, "Usage: %s [parameters] [--] [boot filename]\n", progname);
std::fprintf(stderr, "\n");
std::fprintf(stderr, " -help: Displays this information and exits.\n");
std::fprintf(stderr, " -version: Displays version information and exits.\n");
std::fprintf(stderr, " -batch: Enables batch mode (exits after powering off).\n");
std::fprintf(stderr, " -fastboot: Force fast boot for provided filename.\n");
std::fprintf(stderr, " -slowboot: Force slow boot for provided filename.\n");
std::fprintf(stderr, " -resume: Load resume save state. If a boot filename is provided,\n"
" that game's resume state will be loaded, otherwise the most\n"
" recent resume save state will be loaded.\n");
std::fprintf(stderr, " -state <index>: Loads specified save state by index.\n");
std::fprintf(stderr, " -statefile <filename>: Loads state from the specified filename.\n"
" No boot filename is required with this option.\n");
std::fprintf(stderr, " -fullscreen: Enters fullscreen mode immediately after starting.\n");
std::fprintf(stderr, " -nofullscreen: Prevents fullscreen mode from triggering if enabled.\n");
std::fprintf(stderr, " -portable: Forces \"portable mode\", data in same directory.\n");
std::fprintf(stderr, " -settings <filename>: Loads a custom settings configuration from the\n"
" specified filename. Default settings applied if file not found.\n");
std::fprintf(stderr, " --: Signals that no more arguments will follow and the remaining\n"
" parameters make up the filename. Use when the filename contains\n"
" spaces or starts with a dash.\n");
std::fprintf(stderr, "\n");
}
static std::shared_ptr<VMBootParameters>& AutoBoot(std::shared_ptr<VMBootParameters>& autoboot)
{
if (!autoboot)
{
autoboot = std::make_shared<VMBootParameters>();
autoboot->source_type = CDVD_SourceType::NoDisc;
}
return autoboot;
}
static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBootParameters>& autoboot)
{
std::optional<bool> fast_boot;
std::optional<bool> start_fullscreen;
std::optional<s32> state_index;
std::string state_filename;
bool no_more_args = false;
for (int i = 1; i < argc; i++)
{
if (!no_more_args)
{
#define CHECK_ARG(str) !std::strcmp(argv[i], str)
#define CHECK_ARG_PARAM(str) (!std::strcmp(argv[i], str) && ((i + 1) < argc))
if (CHECK_ARG("-help"))
{
PrintCommandLineHelp(argv[0]);
return false;
}
else if (CHECK_ARG("-version"))
{
PrintCommandLineVersion();
return false;
}
else if (CHECK_ARG("-batch"))
{
Console.WriteLn("Enabling batch mode.");
AutoBoot(autoboot)->batch_mode = true;
continue;
}
else if (CHECK_ARG("-fastboot"))
{
Console.WriteLn("Forcing fast boot.");
fast_boot = true;
continue;
}
else if (CHECK_ARG("-slowboot"))
{
Console.WriteLn("Forcing slow boot.");
fast_boot = false;
continue;
}
else if (CHECK_ARG("-resume"))
{
state_index = -1;
continue;
}
else if (CHECK_ARG_PARAM("-state"))
{
state_index = std::atoi(argv[++i]);
continue;
}
else if (CHECK_ARG_PARAM("-statefile"))
{
AutoBoot(autoboot)->save_state = argv[++i];
continue;
}
else if (CHECK_ARG_PARAM("-elf"))
{
AutoBoot(autoboot)->elf_override = argv[++i];
continue;
}
else if (CHECK_ARG("-fullscreen"))
{
Console.WriteLn("Going fullscreen after booting.");
start_fullscreen = true;
continue;
}
else if (CHECK_ARG("-nofullscreen"))
{
Console.WriteLn("Preventing fullscreen after booting.");
start_fullscreen = false;
continue;
}
else if (CHECK_ARG("-portable"))
{
Console.WriteLn("Using portable mode.");
// SetUserDirectoryToProgramDirectory();
continue;
}
else if (CHECK_ARG("-resume"))
{
state_index = -1;
continue;
}
else if (CHECK_ARG("--"))
{
no_more_args = true;
continue;
}
else if (argv[i][0] == '-')
{
Console.Error("Unknown parameter: '%s'", argv[i]);
return false;
}
#undef CHECK_ARG
#undef CHECK_ARG_PARAM
}
if (!AutoBoot(autoboot)->source.empty())
AutoBoot(autoboot)->source += ' ';
else
AutoBoot(autoboot)->source_type = CDVD_SourceType::Iso;
AutoBoot(autoboot)->source += argv[i];
}
return true;
}
int main(int argc, char* argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
#endif
QApplication app(argc, argv);
std::shared_ptr<VMBootParameters> autoboot;
if (!ParseCommandLineOptions(argc, argv, autoboot))
return EXIT_FAILURE;
MainWindow* main_window = new MainWindow(QApplication::style()->objectName());
if (!QtHost::Initialize())
{
delete main_window;
return EXIT_FAILURE;
}
main_window->initialize();
EmuThread::start();
main_window->refreshGameList(false);
main_window->show();
if (autoboot)
g_emu_thread->startVM(std::move(autoboot));
const int result = app.exec();
EmuThread::stop();
QtHost::Shutdown();
return result;
}
#ifdef _WIN32
// Apparently Qt6 got rid of this?
#include "common/RedtapeWindows.h"
#include <shellapi.h>
/*
WinMain() - Initializes Windows and calls user's startup function main().
NOTE: WinMain() won't be called if the application was linked as a "console"
application.
*/
// Convert a wchar_t to char string, equivalent to QString::toLocal8Bit()
// when passed CP_ACP.
static inline char* wideToMulti(unsigned int codePage, const wchar_t* aw)
{
const int required = WideCharToMultiByte(codePage, 0, aw, -1, nullptr, 0, nullptr, nullptr);
char* result = new char[required];
WideCharToMultiByte(codePage, 0, aw, -1, result, required, nullptr, nullptr);
return result;
}
extern "C" int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR /*cmdParamarg*/, int /* cmdShow */)
{
int argc = 0;
wchar_t** argvW = CommandLineToArgvW(GetCommandLineW(), &argc);
if (argvW == nullptr)
return -1;
char** argv = new char*[argc + 1];
for (int i = 0; i != argc; ++i)
argv[i] = wideToMulti(CP_ACP, argvW[i]);
argv[argc] = nullptr;
LocalFree(argvW);
const int exitCode = main(argc, argv);
for (int i = 0; (i != argc) && (argv[i] != nullptr); ++i)
delete[] argv[i];
delete[] argv;
return exitCode;
}
#endif

1372
pcsx2-qt/MainWindow.cpp Normal file

File diff suppressed because it is too large Load Diff

177
pcsx2-qt/MainWindow.h Normal file
View File

@ -0,0 +1,177 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtWidgets/QMainWindow>
#include <optional>
#include "Settings/ControllerSettingsDialog.h"
#include "Settings/SettingsDialog.h"
#include "ui_MainWindow.h"
class QProgressBar;
class DisplayWidget;
class DisplayContainer;
class GameListWidget;
class ControllerSettingsDialog;
class EmuThread;
namespace GameList
{
struct Entry;
}
class MainWindow final : public QMainWindow
{
Q_OBJECT
public:
static const char* DEFAULT_THEME_NAME;
public:
explicit MainWindow(const QString& unthemed_style_name);
~MainWindow();
void initialize();
void connectVMThreadSignals(EmuThread* thread);
public Q_SLOTS:
void refreshGameList(bool invalidate_cache);
void invalidateSaveStateCache();
void reportError(const QString& title, const QString& message);
private Q_SLOTS:
DisplayWidget* createDisplay(bool fullscreen, bool render_to_main);
DisplayWidget* updateDisplay(bool fullscreen, bool render_to_main);
void displayResizeRequested(qint32 width, qint32 height);
void destroyDisplay();
void focusDisplayWidget();
void onGameListRefreshComplete();
void onGameListRefreshProgress(const QString& status, int current, int total);
void onGameListSelectionChanged();
void onGameListEntryActivated();
void onGameListEntryContextMenuRequested(const QPoint& point);
void onStartFileActionTriggered();
void onStartBIOSActionTriggered();
void onChangeDiscFromFileActionTriggered();
void onChangeDiscFromGameListActionTriggered();
void onChangeDiscFromDeviceActionTriggered();
void onChangeDiscMenuAboutToShow();
void onChangeDiscMenuAboutToHide();
void onLoadStateMenuAboutToShow();
void onSaveStateMenuAboutToShow();
void onViewToolbarActionToggled(bool checked);
void onViewLockToolbarActionToggled(bool checked);
void onViewStatusBarActionToggled(bool checked);
void onViewGameListActionTriggered();
void onViewGameGridActionTriggered();
void onViewSystemDisplayTriggered();
void onViewGamePropertiesActionTriggered();
void onGitHubRepositoryActionTriggered();
void onSupportForumsActionTriggered();
void onDiscordServerActionTriggered();
void onAboutActionTriggered();
void onCheckForUpdatesActionTriggered();
void onToolsOpenDataDirectoryTriggered();
void onThemeChanged();
void onThemeChangedFromSettings();
void onVMStarting();
void onVMStarted();
void onVMPaused();
void onVMResumed();
void onVMStopped();
void onGameChanged(const QString& path, const QString& serial, const QString& name, quint32 crc);
void recreate();
protected:
void closeEvent(QCloseEvent* event);
private:
enum : s32
{
NUM_SAVE_STATE_SLOTS = 10,
};
void setupAdditionalUi();
void connectSignals();
void setStyleFromSettings();
void setIconThemeFromSettings();
void saveStateToConfig();
void restoreStateFromConfig();
void updateEmulationActions(bool starting, bool running);
void updateWindowTitle();
void setProgressBar(int current, int total);
void clearProgressBar();
bool isShowingGameList() const;
void switchToGameListView();
void switchToEmulationView();
QWidget* getDisplayContainer() const;
void saveDisplayWindowGeometryToConfig();
void restoreDisplayWindowGeometryFromConfig();
void destroyDisplayWidget();
void setDisplayFullscreen(const std::string& fullscreen_mode);
SettingsDialog* getSettingsDialog();
void doSettings(SettingsDialog::Category category = SettingsDialog::Category::Count);
ControllerSettingsDialog* getControllerSettingsDialog();
void doControllerSettings(ControllerSettingsDialog::Category category = ControllerSettingsDialog::Category::Count);
void startGameListEntry(const GameList::Entry* entry, std::optional<s32> save_slot = std::nullopt,
std::optional<bool> fast_boot = std::nullopt);
void setGameListEntryCoverImage(const GameList::Entry* entry);
void loadSaveStateSlot(s32 slot);
void loadSaveStateFile(const QString& filename, const QString& state_filename);
void populateLoadStateMenu(QMenu* menu, const QString& filename, const QString& serial, quint32 crc);
void populateSaveStateMenu(QMenu* menu, const QString& serial, quint32 crc);
void updateSaveStateMenus(const QString& filename, const QString& serial, quint32 crc);
Ui::MainWindow m_ui;
QString m_unthemed_style_name;
GameListWidget* m_game_list_widget = nullptr;
DisplayWidget* m_display_widget = nullptr;
DisplayContainer* m_display_container = nullptr;
SettingsDialog* m_settings_dialog = nullptr;
ControllerSettingsDialog* m_controller_settings_dialog = nullptr;
QProgressBar* m_status_progress_widget = nullptr;
QString m_current_disc_path;
QString m_current_game_serial;
QString m_current_game_name;
quint32 m_current_game_crc;
bool m_vm_valid = false;
bool m_vm_paused = false;
bool m_save_states_invalidated = false;
bool m_was_focused_on_container_switch = false;
};
extern MainWindow* g_main_window;

648
pcsx2-qt/MainWindow.ui Normal file
View File

@ -0,0 +1,648 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>700</height>
</rect>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>PCSX2</string>
</property>
<property name="windowIcon">
<iconset resource="resources/resources.qrc">
<normaloff>:/icons/AppIcon.png</normaloff>:/icons/AppIcon.png</iconset>
</property>
<widget class="QStackedWidget" name="mainContainer">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page"/>
<widget class="QWidget" name="page_2"/>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuSystem">
<property name="title">
<string>&amp;System</string>
</property>
<widget class="QMenu" name="menuChangeDisc">
<property name="title">
<string>Change Disc</string>
</property>
<property name="icon">
<iconset theme="dvd-line"/>
</property>
<actiongroup name="actionGroupChangeDiscSubImages"/>
<addaction name="actionChangeDiscFromFile"/>
<addaction name="actionChangeDiscFromDevice"/>
<addaction name="actionChangeDiscFromGameList"/>
<addaction name="actionRemoveDisc"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menuCheats">
<property name="title">
<string>Cheats</string>
</property>
<property name="icon">
<iconset theme="flask-line"/>
</property>
</widget>
<widget class="QMenu" name="menuLoadState">
<property name="title">
<string>Load State</string>
</property>
<property name="icon">
<iconset theme="folder-open-line"/>
</property>
</widget>
<widget class="QMenu" name="menuSaveState">
<property name="title">
<string>Save State</string>
</property>
<property name="icon">
<iconset theme="save-3-line"/>
</property>
</widget>
<addaction name="actionStartFile"/>
<addaction name="actionStartDisc"/>
<addaction name="actionStartBios"/>
<addaction name="separator"/>
<addaction name="actionPowerOff"/>
<addaction name="actionReset"/>
<addaction name="actionPause"/>
<addaction name="menuChangeDisc"/>
<addaction name="separator"/>
<addaction name="menuCheats"/>
<addaction name="actionScreenshot"/>
<addaction name="separator"/>
<addaction name="menuLoadState"/>
<addaction name="menuSaveState"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuSettings">
<property name="title">
<string>S&amp;ettings</string>
</property>
<addaction name="actionInterfaceSettings"/>
<addaction name="actionGameListSettings"/>
<addaction name="actionBIOSSettings"/>
<addaction name="actionEmulationSettings"/>
<addaction name="actionSystemSettings"/>
<addaction name="actionGraphicsSettings"/>
<addaction name="actionAudioSettings"/>
<addaction name="actionMemoryCardSettings"/>
<addaction name="actionControllerSettings"/>
<addaction name="actionHotkeySettings"/>
<addaction name="separator"/>
<addaction name="actionAddGameDirectory"/>
<addaction name="actionScanForNewGames"/>
<addaction name="actionRescanAllGames"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="actionGitHubRepository"/>
<addaction name="actionSupportForums"/>
<addaction name="actionDiscordServer"/>
<addaction name="separator"/>
<addaction name="actionCheckForUpdates"/>
<addaction name="separator"/>
<addaction name="actionAboutQt"/>
<addaction name="actionAbout"/>
</widget>
<widget class="QMenu" name="menuDebug">
<property name="title">
<string>&amp;Debug</string>
</property>
<widget class="QMenu" name="menuDebugSwitchRenderer">
<property name="title">
<string>Switch Renderer</string>
</property>
</widget>
<addaction name="separator"/>
<addaction name="actionToggleSoftwareRendering"/>
<addaction name="menuDebugSwitchRenderer"/>
<addaction name="separator"/>
<addaction name="actionReloadPatches"/>
</widget>
<widget class="QMenu" name="menu_View">
<property name="title">
<string>&amp;View</string>
</property>
<widget class="QMenu" name="menuWindowSize">
<property name="title">
<string>&amp;Window Size</string>
</property>
<property name="icon">
<iconset theme="window-2-line"/>
</property>
</widget>
<addaction name="actionViewToolbar"/>
<addaction name="actionViewLockToolbar"/>
<addaction name="actionViewStatusBar"/>
<addaction name="separator"/>
<addaction name="actionViewGameList"/>
<addaction name="actionViewGameGrid"/>
<addaction name="actionViewSystemDisplay"/>
<addaction name="actionViewGameProperties"/>
<addaction name="separator"/>
<addaction name="actionFullscreen"/>
<addaction name="menuWindowSize"/>
<addaction name="separator"/>
<addaction name="actionGridViewShowTitles"/>
<addaction name="actionGridViewZoomIn"/>
<addaction name="actionGridViewZoomOut"/>
<addaction name="actionGridViewRefreshCovers"/>
</widget>
<widget class="QMenu" name="menu_Tools">
<property name="title">
<string>&amp;Tools</string>
</property>
<addaction name="actionOpenDataDirectory"/>
</widget>
<addaction name="menuSystem"/>
<addaction name="menuSettings"/>
<addaction name="menu_View"/>
<addaction name="menu_Tools"/>
<addaction name="menuDebug"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextUnderIcon</enum>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<property name="visible">
<bool>false</bool>
</property>
<addaction name="actionStartFile"/>
<addaction name="actionStartDisc"/>
<addaction name="actionStartBios"/>
<addaction name="separator"/>
<addaction name="actionPowerOff"/>
<addaction name="actionReset"/>
<addaction name="actionPause"/>
<addaction name="actionChangeDisc"/>
<addaction name="actionCheats"/>
<addaction name="actionScreenshot"/>
<addaction name="separator"/>
<addaction name="actionLoadState"/>
<addaction name="actionSaveState"/>
<addaction name="separator"/>
<addaction name="actionFullscreen"/>
<addaction name="separator"/>
<addaction name="actionSettings"/>
<addaction name="actionControllerSettings"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<action name="actionStartFile">
<property name="text">
<string>Start &amp;File...</string>
</property>
<property name="icon">
<iconset theme="file-line"/>
</property>
</action>
<action name="actionStartDisc">
<property name="text">
<string>Start &amp;Disc...</string>
</property>
<property name="icon">
<iconset theme="disc-line"/>
</property>
</action>
<action name="actionStartBios">
<property name="text">
<string>Start &amp;BIOS</string>
</property>
<property name="icon">
<iconset theme="hard-drive-2-line"/>
</property>
</action>
<action name="actionScanForNewGames">
<property name="text">
<string>&amp;Scan For New Games</string>
</property>
<property name="icon">
<iconset theme="file-search-line"/>
</property>
</action>
<action name="actionRescanAllGames">
<property name="text">
<string>&amp;Rescan All Games</string>
</property>
<property name="icon">
<iconset theme="refresh-line"/>
</property>
</action>
<action name="actionPowerOff">
<property name="text">
<string>Shut &amp;Down</string>
</property>
<property name="icon">
<iconset theme="shut-down-line"/>
</property>
</action>
<action name="actionReset">
<property name="text">
<string>&amp;Reset</string>
</property>
<property name="icon">
<iconset theme="restart-line"/>
</property>
</action>
<action name="actionPause">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Pause</string>
</property>
<property name="icon">
<iconset theme="pause-line"/>
</property>
</action>
<action name="actionLoadState">
<property name="text">
<string>&amp;Load State</string>
</property>
<property name="icon">
<iconset theme="folder-open-line"/>
</property>
</action>
<action name="actionSaveState">
<property name="text">
<string>&amp;Save State</string>
</property>
<property name="icon">
<iconset theme="save-3-line"/>
</property>
</action>
<action name="actionExit">
<property name="text">
<string>E&amp;xit</string>
</property>
<property name="icon">
<iconset theme="door-open-line"/>
</property>
</action>
<action name="actionBIOSSettings">
<property name="text">
<string>&amp;BIOS</string>
</property>
<property name="icon">
<iconset theme="hard-drive-2-line"/>
</property>
</action>
<action name="actionSystemSettings">
<property name="text">
<string>System</string>
</property>
<property name="icon">
<iconset theme="artboard-2-line"/>
</property>
</action>
<action name="actionEmulationSettings">
<property name="text">
<string>Emulation</string>
</property>
<property name="icon">
<iconset theme="dashboard-line"/>
</property>
</action>
<action name="actionControllerSettings">
<property name="text">
<string>&amp;Controllers</string>
</property>
<property name="icon">
<iconset theme="gamepad-line"/>
</property>
</action>
<action name="actionHotkeySettings">
<property name="text">
<string>&amp;Hotkeys</string>
</property>
<property name="icon">
<iconset theme="keyboard-line"/>
</property>
</action>
<action name="actionGraphicsSettings">
<property name="text">
<string>&amp;Graphics</string>
</property>
<property name="icon">
<iconset theme="brush-line"/>
</property>
</action>
<action name="actionPostProcessingSettings">
<property name="text">
<string>&amp;Post-Processing Settings...</string>
</property>
</action>
<action name="actionFullscreen">
<property name="text">
<string>Fullscreen</string>
</property>
<property name="icon">
<iconset theme="fullscreen-line"/>
</property>
</action>
<action name="actionResolution_Scale">
<property name="text">
<string>Resolution Scale</string>
</property>
</action>
<action name="actionGitHubRepository">
<property name="text">
<string>&amp;GitHub Repository...</string>
</property>
</action>
<action name="actionSupportForums">
<property name="text">
<string>Support &amp;Forums...</string>
</property>
</action>
<action name="actionDiscordServer">
<property name="text">
<string>&amp;Discord Server...</string>
</property>
</action>
<action name="actionCheckForUpdates">
<property name="icon">
<iconset theme="download-2-line"/>
</property>
<property name="text">
<string>Check for &amp;Updates...</string>
</property>
</action>
<action name="actionAboutQt">
<property name="icon">
<iconset resource="resources/resources.qrc">
<normaloff>:/icons/QT.png</normaloff>:/icons/QT.png</iconset>
</property>
<property name="text">
<string>About &amp;Qt...</string>
</property>
</action>
<action name="actionAbout">
<property name="text">
<string>&amp;About PCSX2...</string>
</property>
</action>
<action name="actionChangeDisc">
<property name="text">
<string>Change Disc...</string>
</property>
<property name="icon">
<iconset theme="dvd-line"/>
</property>
</action>
<action name="actionCheats">
<property name="text">
<string>Cheats...</string>
</property>
<property name="icon">
<iconset theme="flask-line"/>
</property>
</action>
<action name="actionAudioSettings">
<property name="text">
<string>&amp;Audio</string>
</property>
<property name="icon">
<iconset theme="volume-up-line"/>
</property>
</action>
<action name="actionGameListSettings">
<property name="text">
<string>Game List</string>
</property>
<property name="icon">
<iconset theme="folder-settings-line"/>
</property>
</action>
<action name="actionInterfaceSettings">
<property name="text">
<string>Interface</string>
</property>
<property name="icon">
<iconset theme="settings-3-line"/>
</property>
</action>
<action name="actionAddGameDirectory">
<property name="text">
<string>Add Game Directory...</string>
</property>
<property name="icon">
<iconset theme="folder-add-line"/>
</property>
</action>
<action name="actionSettings">
<property name="text">
<string>&amp;Settings...</string>
</property>
<property name="icon">
<iconset theme="settings-3-line"/>
</property>
</action>
<action name="actionChangeDiscFromFile">
<property name="text">
<string>From File...</string>
</property>
</action>
<action name="actionChangeDiscFromDevice">
<property name="text">
<string>From Device...</string>
</property>
</action>
<action name="actionChangeDiscFromGameList">
<property name="text">
<string>From Game List...</string>
</property>
</action>
<action name="actionRemoveDisc">
<property name="text">
<string>Remove Disc</string>
</property>
</action>
<action name="actionGlobal_State">
<property name="text">
<string>Global State</string>
</property>
</action>
<action name="actionScreenshot">
<property name="text">
<string>&amp;Screenshot</string>
</property>
<property name="icon">
<iconset theme="screenshot-2-line"/>
</property>
</action>
<action name="actionMemoryCardSettings">
<property name="text">
<string>&amp;Memory Cards</string>
</property>
<property name="icon">
<iconset theme="sd-card-line"/>
</property>
</action>
<action name="actionViewToolbar">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Toolbar</string>
</property>
</action>
<action name="actionViewLockToolbar">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="text">
<string>Lock Toolbar</string>
</property>
</action>
<action name="actionViewStatusBar">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Status Bar</string>
</property>
</action>
<action name="actionViewGameList">
<property name="text">
<string>Game &amp;List</string>
</property>
<property name="icon">
<iconset theme="list-check"/>
</property>
</action>
<action name="actionViewSystemDisplay">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>System &amp;Display</string>
</property>
<property name="icon">
<iconset theme="tv-2-line"/>
</property>
</action>
<action name="actionViewGameProperties">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Game &amp;Properties</string>
</property>
<property name="icon">
<iconset theme="file-settings-line"/>
</property>
</action>
<action name="actionViewGameGrid">
<property name="text">
<string>Game &amp;Grid</string>
</property>
<property name="icon">
<iconset theme="function-line"/>
</property>
</action>
<action name="actionGridViewShowTitles">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Show Titles (Grid View)</string>
</property>
</action>
<action name="actionGridViewZoomIn">
<property name="text">
<string>Zoom &amp;In (Grid View)</string>
</property>
<property name="shortcut">
<string>Ctrl++</string>
</property>
</action>
<action name="actionGridViewZoomOut">
<property name="text">
<string>Zoom &amp;Out (Grid View)</string>
</property>
<property name="shortcut">
<string>Ctrl+-</string>
</property>
</action>
<action name="actionGridViewRefreshCovers">
<property name="text">
<string>Refresh &amp;Covers (Grid View)</string>
</property>
</action>
<action name="actionOpen_Memory_Card_Directory">
<property name="text">
<string>Open Memory Card Directory...</string>
</property>
</action>
<action name="actionOpenDataDirectory">
<property name="text">
<string>Open Data Directory...</string>
</property>
</action>
<action name="actionToggleSoftwareRendering">
<property name="text">
<string>Toggle Software Rendering</string>
</property>
</action>
<action name="actionReloadPatches">
<property name="text">
<string>Reload Cheats/Patches</string>
</property>
</action>
</widget>
<resources>
<include location="resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,16 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"

View File

@ -0,0 +1,21 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "pcsx2/PrecompiledHeader.h"
// Needed because of moc shenanigans with pch.
#include <memory>
#include <QtCore/QtCore>

506
pcsx2-qt/QtHost.cpp Normal file
View File

@ -0,0 +1,506 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/FileSystem.h"
#include "common/SettingsWrapper.h"
#include "common/StringUtil.h"
#include "pcsx2/Frontend/GameList.h"
#include "pcsx2/Frontend/INISettingsInterface.h"
#include "pcsx2/HostSettings.h"
#include "pcsx2/PAD/Host/PAD.h"
#include <QtCore/QTimer>
#include <QtWidgets/QMessageBox>
#include "EmuThread.h"
#include "GameList/GameListWidget.h"
#include "MainWindow.h"
#include "QtHost.h"
#include "pcsx2/DebugTools/Debug.h"
static constexpr u32 SETTINGS_VERSION = 1;
static constexpr u32 SETTINGS_SAVE_DELAY = 1000;
//////////////////////////////////////////////////////////////////////////
// Local function declarations
//////////////////////////////////////////////////////////////////////////
static void InitializeWxRubbish();
static bool InitializeConfig();
static void SetDefaultConfig();
static void QueueSettingsSave();
static void SaveSettings();
//////////////////////////////////////////////////////////////////////////
// Local variable declarations
//////////////////////////////////////////////////////////////////////////
static std::unique_ptr<QTimer> s_settings_save_timer;
static std::unique_ptr<INISettingsInterface> s_base_settings_interface;
//////////////////////////////////////////////////////////////////////////
// Initialization/Shutdown
//////////////////////////////////////////////////////////////////////////
bool QtHost::Initialize()
{
qRegisterMetaType<std::shared_ptr<VMBootParameters>>();
qRegisterMetaType<GSRendererType>();
qRegisterMetaType<const GameList::Entry*>();
qRegisterMetaType<InputBindingKey>();
InitializeWxRubbish();
if (!InitializeConfig())
{
Console.WriteLn("Failed to initialize config.");
return false;
}
return true;
}
void QtHost::Shutdown() {}
static bool SetCriticalFolders()
{
std::string program_path(FileSystem::GetProgramPath());
EmuFolders::AppRoot = wxDirName(wxFileName(StringUtil::UTF8StringToWxString(program_path)));
EmuFolders::DataRoot = EmuFolders::AppRoot;
#ifndef _WIN32
const char* homedir = getenv("HOME");
if (homedir)
EmuFolders::DataRoot = Path::Combine(wxString::FromUTF8(homedir), wxString(L"PCSX2"));
#endif
EmuFolders::Settings = EmuFolders::DataRoot.Combine(wxDirName(L"inis"));
EmuFolders::Resources = EmuFolders::AppRoot.Combine(wxDirName(L"resources"));
// the resources directory should exist, bail out if not
if (!EmuFolders::Resources.Exists())
{
QMessageBox::critical(nullptr, QStringLiteral("Error"),
QStringLiteral("Resources directory is missing, your installation is incomplete."));
return false;
}
return true;
}
void QtHost::UpdateFolders()
{
// TODO: This should happen with the VM thread paused.
auto lock = Host::GetSettingsLock();
EmuFolders::LoadConfig(*s_base_settings_interface.get());
EmuFolders::EnsureFoldersExist();
}
bool InitializeConfig()
{
if (!SetCriticalFolders())
return false;
const std::string path(Path::CombineStdString(EmuFolders::Settings, "PCSX2.ini"));
s_base_settings_interface = std::make_unique<INISettingsInterface>(std::move(path));
Host::Internal::SetBaseSettingsLayer(s_base_settings_interface.get());
uint settings_version;
if (!s_base_settings_interface->Load() ||
!s_base_settings_interface->GetUIntValue("UI", "SettingsVersion", &settings_version) ||
settings_version != SETTINGS_VERSION)
{
QMessageBox::critical(
g_main_window, qApp->translate("QtHost", "Settings Reset"),
qApp->translate("QtHost", "Settings do not exist or are the incorrect version, resetting to defaults."));
SetDefaultConfig();
s_base_settings_interface->Save();
}
// TODO: Handle reset to defaults if load fails.
EmuFolders::LoadConfig(*s_base_settings_interface.get());
EmuFolders::EnsureFoldersExist();
QtHost::UpdateLogging();
return true;
}
void SetDefaultConfig()
{
EmuConfig = Pcsx2Config();
EmuFolders::SetDefaults();
SettingsInterface& si = *s_base_settings_interface.get();
si.SetUIntValue("UI", "SettingsVersion", SETTINGS_VERSION);
{
SettingsSaveWrapper wrapper(si);
EmuConfig.LoadSave(wrapper);
}
EmuFolders::Save(si);
PAD::SetDefaultConfig(si);
}
std::string QtHost::GetBaseStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/)
{
auto lock = Host::GetSettingsLock();
return s_base_settings_interface->GetStringValue(section, key, default_value);
}
bool QtHost::GetBaseBoolSettingValue(const char* section, const char* key, bool default_value /*= false*/)
{
auto lock = Host::GetSettingsLock();
return s_base_settings_interface->GetBoolValue(section, key, default_value);
}
int QtHost::GetBaseIntSettingValue(const char* section, const char* key, int default_value /*= 0*/)
{
auto lock = Host::GetSettingsLock();
return s_base_settings_interface->GetIntValue(section, key, default_value);
}
float QtHost::GetBaseFloatSettingValue(const char* section, const char* key, float default_value /*= 0.0f*/)
{
auto lock = Host::GetSettingsLock();
return s_base_settings_interface->GetFloatValue(section, key, default_value);
}
std::vector<std::string> QtHost::GetBaseStringListSetting(const char* section, const char* key)
{
auto lock = Host::GetSettingsLock();
return s_base_settings_interface->GetStringList(section, key);
}
void QtHost::SetBaseBoolSettingValue(const char* section, const char* key, bool value)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->SetBoolValue(section, key, value);
QueueSettingsSave();
}
void QtHost::SetBaseIntSettingValue(const char* section, const char* key, int value)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->SetIntValue(section, key, value);
QueueSettingsSave();
}
void QtHost::SetBaseFloatSettingValue(const char* section, const char* key, float value)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->SetFloatValue(section, key, value);
QueueSettingsSave();
}
void QtHost::SetBaseStringSettingValue(const char* section, const char* key, const char* value)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->SetStringValue(section, key, value);
QueueSettingsSave();
}
void QtHost::SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->SetStringList(section, key, values);
QueueSettingsSave();
}
bool QtHost::AddBaseValueToStringList(const char* section, const char* key, const char* value)
{
auto lock = Host::GetSettingsLock();
if (!s_base_settings_interface->AddToStringList(section, key, value))
return false;
QueueSettingsSave();
return true;
}
bool QtHost::RemoveBaseValueFromStringList(const char* section, const char* key, const char* value)
{
auto lock = Host::GetSettingsLock();
if (!s_base_settings_interface->RemoveFromStringList(section, key, value))
return false;
QueueSettingsSave();
return true;
}
void QtHost::RemoveBaseSettingValue(const char* section, const char* key)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->DeleteValue(section, key);
QueueSettingsSave();
}
void SaveSettings()
{
pxAssertRel(!g_emu_thread->isOnEmuThread(), "Saving should happen on the UI thread.");
{
auto lock = Host::GetSettingsLock();
if (!s_base_settings_interface->Save())
Console.Error("Failed to save settings.");
}
s_settings_save_timer->deleteLater();
s_settings_save_timer.release();
}
void QueueSettingsSave()
{
if (s_settings_save_timer)
return;
s_settings_save_timer = std::make_unique<QTimer>();
s_settings_save_timer->connect(s_settings_save_timer.get(), &QTimer::timeout, SaveSettings);
s_settings_save_timer->setSingleShot(true);
s_settings_save_timer->start(SETTINGS_SAVE_DELAY);
}
std::optional<std::vector<u8>> Host::ReadResourceFile(const char* filename)
{
const std::string path(Path::CombineStdString(EmuFolders::Resources, filename));
std::optional<std::vector<u8>> ret(FileSystem::ReadBinaryFile(path.c_str()));
if (!ret.has_value())
Console.Error("Failed to read resource file '%s'", filename);
return ret;
}
std::optional<std::string> Host::ReadResourceFileToString(const char* filename)
{
const std::string path(Path::CombineStdString(EmuFolders::Resources, filename));
std::optional<std::string> ret(FileSystem::ReadFileToString(path.c_str()));
if (!ret.has_value())
Console.Error("Failed to read resource file to string '%s'", filename);
return ret;
}
void Host::ReportErrorAsync(const std::string_view& title, const std::string_view& message)
{
if (!title.empty() && !message.empty())
{
Console.Error("ReportErrorAsync: %*s: %*s",
static_cast<int>(title.size()), title.data(),
static_cast<int>(message.size()), message.data());
}
else if (!message.empty())
{
Console.Error("ReportErrorAsync: %*s",
static_cast<int>(message.size()), message.data());
}
QMetaObject::invokeMethod(g_main_window, "reportError", Qt::QueuedConnection,
Q_ARG(const QString&, title.empty() ? QString() : QString::fromUtf8(title.data(), title.size())),
Q_ARG(const QString&, message.empty() ? QString() : QString::fromUtf8(message.data(), message.size())));
}
void Host::OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name)
{
emit g_emu_thread->onInputDeviceConnected(
identifier.empty() ? QString() : QString::fromUtf8(identifier.data(), identifier.size()),
device_name.empty() ? QString() : QString::fromUtf8(device_name.data(), device_name.size()));
}
void Host::OnInputDeviceDisconnected(const std::string_view& identifier)
{
emit g_emu_thread->onInputDeviceDisconnected(
identifier.empty() ? QString() : QString::fromUtf8(identifier.data(), identifier.size()));
}
//////////////////////////////////////////////////////////////////////////
// Interface Stuff
//////////////////////////////////////////////////////////////////////////
const IConsoleWriter* PatchesCon = &Console;
void LoadAllPatchesAndStuff(const Pcsx2Config& cfg)
{
// FIXME
}
void PatchesVerboseReset()
{
// FIXME
}
// Replacement for Console so we actually get output to our console window on Windows.
#ifdef _WIN32
#include "common/RedtapeWindows.h"
static bool s_debugger_attached = false;
static bool s_console_handle_set = false;
static HANDLE s_console_handle = nullptr;
static void __concall ConsoleWinQt_SetTitle(const wxString& title)
{
SetConsoleTitleW(title.wc_str());
}
static void __concall ConsoleWinQt_DoSetColor(ConsoleColors color)
{
if (!s_console_handle)
return;
static constexpr WORD colors[ConsoleColors_Count] = {
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // default
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // black
FOREGROUND_GREEN, // green
FOREGROUND_RED, // red
FOREGROUND_BLUE, // blue
FOREGROUND_RED | FOREGROUND_BLUE, // magenta
FOREGROUND_RED | FOREGROUND_GREEN, // orange
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // gray
FOREGROUND_BLUE | FOREGROUND_INTENSITY, // cyan
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, // yellow
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, // white
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // strong black
FOREGROUND_RED | FOREGROUND_INTENSITY, // strong red
FOREGROUND_GREEN | FOREGROUND_INTENSITY, // strong green
FOREGROUND_BLUE | FOREGROUND_INTENSITY, // strong blue
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY, // strong magenta
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, // strong orange
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // strong gray
FOREGROUND_BLUE | FOREGROUND_INTENSITY, // strong cyan
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, // strong yellow
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, // strong white
};
SetConsoleTextAttribute(s_console_handle, colors[static_cast<u32>(color)]);
}
static void __concall ConsoleWinQt_Newline()
{
if (!s_console_handle)
return;
if (s_debugger_attached)
OutputDebugStringW(L"\n");
DWORD written;
WriteConsoleW(s_console_handle, L"\n", 1, &written, nullptr);
}
static void __concall ConsoleWinQt_DoWrite(const wxString& fmt)
{
if (!s_console_handle)
return;
if (s_debugger_attached)
OutputDebugStringW(fmt.wc_str());
DWORD written;
WriteConsoleW(s_console_handle, fmt.wc_str(), static_cast<DWORD>(fmt.size()), &written, nullptr);
}
static void __concall ConsoleWinQt_DoWriteLn(const wxString& fmt)
{
if (!s_console_handle)
return;
if (s_debugger_attached)
{
OutputDebugStringW(fmt.wc_str());
OutputDebugStringW(L"\n");
}
DWORD written;
WriteConsoleW(s_console_handle, fmt.wc_str(), static_cast<DWORD>(fmt.size()), &written, nullptr);
WriteConsoleW(s_console_handle, L"\n", 1, &written, nullptr);
}
static const IConsoleWriter ConsoleWriter_WinQt =
{
ConsoleWinQt_DoWrite,
ConsoleWinQt_DoWriteLn,
ConsoleWinQt_DoSetColor,
ConsoleWinQt_DoWrite,
ConsoleWinQt_Newline,
ConsoleWinQt_SetTitle,
};
#endif
void QtHost::UpdateLogging()
{
// TODO: Make this an actual option.
bool console_logging_enabled = false;
#if defined(_DEBUG) || defined(PCSX2_DEVBUILD)
console_logging_enabled = true;
#endif
DevConWriterEnabled = console_logging_enabled;
SysConsole.eeConsole.Enabled = console_logging_enabled;
SysConsole.iopConsole.Enabled = console_logging_enabled;
if (console_logging_enabled)
{
#ifdef _WIN32
s_debugger_attached = IsDebuggerPresent();
if (!s_console_handle_set)
{
bool handle_valid = (GetConsoleWindow() != NULL);
if (!handle_valid)
{
AllocConsole();
handle_valid = (freopen("CONIN$", "r", stdin) != nullptr);
handle_valid = (freopen("CONOUT$", "w", stdout) != nullptr);
handle_valid = (freopen("CONOUT$", "w", stderr) != nullptr);
}
if (handle_valid)
{
s_console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
s_console_handle_set = true;
}
}
if (!s_console_handle && !s_debugger_attached)
Console_SetActiveHandler(ConsoleWriter_Null);
else
Console_SetActiveHandler(ConsoleWriter_WinQt);
#else
Console_SetActiveHandler(ConsoleWriter_Stdout);
#endif
}
else
{
Console_SetActiveHandler(ConsoleWriter_Null);
}
}
#include <wx/module.h>
#ifdef _WIN32
extern "C" HINSTANCE wxGetInstance();
extern void wxSetInstance(HINSTANCE hInst);
#endif
void InitializeWxRubbish()
{
wxLog::DoCreateOnDemand();
wxLog::GetActiveTarget();
#ifdef _WIN32
if (!wxGetInstance())
wxSetInstance(::GetModuleHandle(NULL));
#endif // _WIN32
wxModule::RegisterModules();
wxModule::InitializeModules();
}

54
pcsx2-qt/QtHost.h Normal file
View File

@ -0,0 +1,54 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "pcsx2/Host.h"
#include "pcsx2/HostDisplay.h"
#include "pcsx2/HostSettings.h"
#include "pcsx2/Frontend/InputManager.h"
#include "pcsx2/VMManager.h"
#include <QtCore/QMetaType>
class SettingsInterface;
class EmuThread;
Q_DECLARE_METATYPE(GSRendererType);
Q_DECLARE_METATYPE(std::shared_ptr<VMBootParameters>);
Q_DECLARE_METATYPE(InputBindingKey);
namespace QtHost
{
bool Initialize();
void Shutdown();
void UpdateFolders();
void UpdateLogging();
/// Thread-safe settings access.
std::string GetBaseStringSettingValue(const char* section, const char* key, const char* default_value = "");
bool GetBaseBoolSettingValue(const char* section, const char* key, bool default_value = false);
int GetBaseIntSettingValue(const char* section, const char* key, int default_value = 0);
float GetBaseFloatSettingValue(const char* section, const char* key, float default_value = 0.0f);
std::vector<std::string> GetBaseStringListSetting(const char* section, const char* key);
void SetBaseBoolSettingValue(const char* section, const char* key, bool value);
void SetBaseIntSettingValue(const char* section, const char* key, int value);
void SetBaseFloatSettingValue(const char* section, const char* key, float value);
void SetBaseStringSettingValue(const char* section, const char* key, const char* value);
void SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values);
bool AddBaseValueToStringList(const char* section, const char* key, const char* value);
bool RemoveBaseValueFromStringList(const char* section, const char* key, const char* value);
void RemoveBaseSettingValue(const char* section, const char* key);
} // namespace QtHost

486
pcsx2-qt/QtKeyCodes.cpp Normal file
View File

@ -0,0 +1,486 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "pcsx2/Frontend/InputManager.h"
struct KeyCodeName
{
int code;
const char* name;
};
static constexpr KeyCodeName s_qt_key_names[] = {
{Qt::Key_Escape, "Escape"},
{Qt::Key_Tab, "Tab"},
{Qt::Key_Backtab, "Backtab"},
{Qt::Key_Backspace, "Backspace"},
{Qt::Key_Return, "Return"},
{Qt::Key_Enter, "Enter"},
{Qt::Key_Insert, "Insert"},
{Qt::Key_Delete, "Delete"},
{Qt::Key_Pause, "Pause"},
{Qt::Key_Print, "Print"},
{Qt::Key_SysReq, "SysReq"},
{Qt::Key_Clear, "Clear"},
{Qt::Key_Home, "Home"},
{Qt::Key_End, "End"},
{Qt::Key_Left, "Left"},
{Qt::Key_Up, "Up"},
{Qt::Key_Right, "Right"},
{Qt::Key_Down, "Down"},
{Qt::Key_PageUp, "PageUp"},
{Qt::Key_PageDown, "PageDown"},
{Qt::Key_Shift, "Shift"},
{Qt::Key_Control, "Control"},
{Qt::Key_Meta, "Meta"},
{Qt::Key_Alt, "Alt"},
{Qt::Key_CapsLock, "CapsLock"},
{Qt::Key_NumLock, "NumLock"},
{Qt::Key_ScrollLock, "ScrollLock"},
{Qt::Key_F1, "F1"},
{Qt::Key_F2, "F2"},
{Qt::Key_F3, "F3"},
{Qt::Key_F4, "F4"},
{Qt::Key_F5, "F5"},
{Qt::Key_F6, "F6"},
{Qt::Key_F7, "F7"},
{Qt::Key_F8, "F8"},
{Qt::Key_F9, "F9"},
{Qt::Key_F10, "F10"},
{Qt::Key_F11, "F11"},
{Qt::Key_F12, "F12"},
{Qt::Key_F13, "F13"},
{Qt::Key_F14, "F14"},
{Qt::Key_F15, "F15"},
{Qt::Key_F16, "F16"},
{Qt::Key_F17, "F17"},
{Qt::Key_F18, "F18"},
{Qt::Key_F19, "F19"},
{Qt::Key_F20, "F20"},
{Qt::Key_F21, "F21"},
{Qt::Key_F22, "F22"},
{Qt::Key_F23, "F23"},
{Qt::Key_F24, "F24"},
{Qt::Key_F25, "F25"},
{Qt::Key_F26, "F26"},
{Qt::Key_F27, "F27"},
{Qt::Key_F28, "F28"},
{Qt::Key_F29, "F29"},
{Qt::Key_F30, "F30"},
{Qt::Key_F31, "F31"},
{Qt::Key_F32, "F32"},
{Qt::Key_F33, "F33"},
{Qt::Key_F34, "F34"},
{Qt::Key_F35, "F35"},
{Qt::Key_Super_L, "Super_L"},
{Qt::Key_Super_R, "Super_R"},
{Qt::Key_Menu, "Menu"},
{Qt::Key_Hyper_L, "Hyper_L"},
{Qt::Key_Hyper_R, "Hyper_R"},
{Qt::Key_Help, "Help"},
{Qt::Key_Direction_L, "Direction_L"},
{Qt::Key_Direction_R, "Direction_R"},
{Qt::Key_Space, "Space"},
{Qt::Key_Any, "Any"},
{Qt::Key_Exclam, "Exclam"},
{Qt::Key_QuoteDbl, "QuoteDbl"},
{Qt::Key_NumberSign, "NumberSign"},
{Qt::Key_Dollar, "Dollar"},
{Qt::Key_Percent, "Percent"},
{Qt::Key_Ampersand, "Ampersand"},
{Qt::Key_Apostrophe, "Apostrophe"},
{Qt::Key_ParenLeft, "ParenLeft"},
{Qt::Key_ParenRight, "ParenRight"},
{Qt::Key_Asterisk, "Asterisk"},
{Qt::Key_Plus, "Plus"},
{Qt::Key_Comma, "Comma"},
{Qt::Key_Minus, "Minus"},
{Qt::Key_Period, "Period"},
{Qt::Key_Slash, "Slash"},
{Qt::Key_0, "0"},
{Qt::Key_1, "1"},
{Qt::Key_2, "2"},
{Qt::Key_3, "3"},
{Qt::Key_4, "4"},
{Qt::Key_5, "5"},
{Qt::Key_6, "6"},
{Qt::Key_7, "7"},
{Qt::Key_8, "8"},
{Qt::Key_9, "9"},
{Qt::Key_Colon, "Colon"},
{Qt::Key_Semicolon, "Semicolon"},
{Qt::Key_Less, "Less"},
{Qt::Key_Equal, "Equal"},
{Qt::Key_Greater, "Greater"},
{Qt::Key_Question, "Question"},
{Qt::Key_At, "At"},
{Qt::Key_A, "A"},
{Qt::Key_B, "B"},
{Qt::Key_C, "C"},
{Qt::Key_D, "D"},
{Qt::Key_E, "E"},
{Qt::Key_F, "F"},
{Qt::Key_G, "G"},
{Qt::Key_H, "H"},
{Qt::Key_I, "I"},
{Qt::Key_J, "J"},
{Qt::Key_K, "K"},
{Qt::Key_L, "L"},
{Qt::Key_M, "M"},
{Qt::Key_N, "N"},
{Qt::Key_O, "O"},
{Qt::Key_P, "P"},
{Qt::Key_Q, "Q"},
{Qt::Key_R, "R"},
{Qt::Key_S, "S"},
{Qt::Key_T, "T"},
{Qt::Key_U, "U"},
{Qt::Key_V, "V"},
{Qt::Key_W, "W"},
{Qt::Key_X, "X"},
{Qt::Key_Y, "Y"},
{Qt::Key_Z, "Z"},
{Qt::Key_BracketLeft, "BracketLeft"},
{Qt::Key_Backslash, "Backslash"},
{Qt::Key_BracketRight, "BracketRight"},
{Qt::Key_AsciiCircum, "AsciiCircum"},
{Qt::Key_Underscore, "Underscore"},
{Qt::Key_QuoteLeft, "QuoteLeft"},
{Qt::Key_BraceLeft, "BraceLeft"},
{Qt::Key_Bar, "Bar"},
{Qt::Key_BraceRight, "BraceRight"},
{Qt::Key_AsciiTilde, "AsciiTilde"},
{Qt::Key_nobreakspace, "nobreakspace"},
{Qt::Key_exclamdown, "exclamdown"},
{Qt::Key_cent, "cent"},
{Qt::Key_sterling, "sterling"},
{Qt::Key_currency, "currency"},
{Qt::Key_yen, "yen"},
{Qt::Key_brokenbar, "brokenbar"},
{Qt::Key_section, "section"},
{Qt::Key_diaeresis, "diaeresis"},
{Qt::Key_copyright, "copyright"},
{Qt::Key_ordfeminine, "ordfeminine"},
{Qt::Key_guillemotleft, "guillemotleft"},
{Qt::Key_notsign, "notsign"},
{Qt::Key_hyphen, "hyphen"},
{Qt::Key_registered, "registered"},
{Qt::Key_macron, "macron"},
{Qt::Key_degree, "degree"},
{Qt::Key_plusminus, "plusminus"},
{Qt::Key_twosuperior, "twosuperior"},
{Qt::Key_threesuperior, "threesuperior"},
{Qt::Key_acute, "acute"},
{Qt::Key_mu, "mu"},
{Qt::Key_paragraph, "paragraph"},
{Qt::Key_periodcentered, "periodcentered"},
{Qt::Key_cedilla, "cedilla"},
{Qt::Key_onesuperior, "onesuperior"},
{Qt::Key_masculine, "masculine"},
{Qt::Key_guillemotright, "guillemotright"},
{Qt::Key_onequarter, "onequarter"},
{Qt::Key_onehalf, "onehalf"},
{Qt::Key_threequarters, "threequarters"},
{Qt::Key_questiondown, "questiondown"},
{Qt::Key_Agrave, "Agrave"},
{Qt::Key_Aacute, "Aacute"},
{Qt::Key_Acircumflex, "Acircumflex"},
{Qt::Key_Atilde, "Atilde"},
{Qt::Key_Adiaeresis, "Adiaeresis"},
{Qt::Key_Aring, "Aring"},
{Qt::Key_AE, "AE"},
{Qt::Key_Ccedilla, "Ccedilla"},
{Qt::Key_Egrave, "Egrave"},
{Qt::Key_Eacute, "Eacute"},
{Qt::Key_Ecircumflex, "Ecircumflex"},
{Qt::Key_Ediaeresis, "Ediaeresis"},
{Qt::Key_Igrave, "Igrave"},
{Qt::Key_Iacute, "Iacute"},
{Qt::Key_Icircumflex, "Icircumflex"},
{Qt::Key_Idiaeresis, "Idiaeresis"},
{Qt::Key_ETH, "ETH"},
{Qt::Key_Ntilde, "Ntilde"},
{Qt::Key_Ograve, "Ograve"},
{Qt::Key_Oacute, "Oacute"},
{Qt::Key_Ocircumflex, "Ocircumflex"},
{Qt::Key_Otilde, "Otilde"},
{Qt::Key_Odiaeresis, "Odiaeresis"},
{Qt::Key_multiply, "multiply"},
{Qt::Key_Ooblique, "Ooblique"},
{Qt::Key_Ugrave, "Ugrave"},
{Qt::Key_Uacute, "Uacute"},
{Qt::Key_Ucircumflex, "Ucircumflex"},
{Qt::Key_Udiaeresis, "Udiaeresis"},
{Qt::Key_Yacute, "Yacute"},
{Qt::Key_THORN, "THORN"},
{Qt::Key_ssharp, "ssharp"},
{Qt::Key_division, "division"},
{Qt::Key_ydiaeresis, "ydiaeresis"},
{Qt::Key_AltGr, "AltGr"},
{Qt::Key_Multi_key, "Multi_key"},
{Qt::Key_Codeinput, "Codeinput"},
{Qt::Key_SingleCandidate, "SingleCandidate"},
{Qt::Key_MultipleCandidate, "MultipleCandidate"},
{Qt::Key_PreviousCandidate, "PreviousCandidate"},
{Qt::Key_Mode_switch, "Mode_switch"},
{Qt::Key_Kanji, "Kanji"},
{Qt::Key_Muhenkan, "Muhenkan"},
{Qt::Key_Henkan, "Henkan"},
{Qt::Key_Romaji, "Romaji"},
{Qt::Key_Hiragana, "Hiragana"},
{Qt::Key_Katakana, "Katakana"},
{Qt::Key_Hiragana_Katakana, "Hiragana_Katakana"},
{Qt::Key_Zenkaku, "Zenkaku"},
{Qt::Key_Hankaku, "Hankaku"},
{Qt::Key_Zenkaku_Hankaku, "Zenkaku_Hankaku"},
{Qt::Key_Touroku, "Touroku"},
{Qt::Key_Massyo, "Massyo"},
{Qt::Key_Kana_Lock, "Kana_Lock"},
{Qt::Key_Kana_Shift, "Kana_Shift"},
{Qt::Key_Eisu_Shift, "Eisu_Shift"},
{Qt::Key_Eisu_toggle, "Eisu_toggle"},
{Qt::Key_Hangul, "Hangul"},
{Qt::Key_Hangul_Start, "Hangul_Start"},
{Qt::Key_Hangul_End, "Hangul_End"},
{Qt::Key_Hangul_Hanja, "Hangul_Hanja"},
{Qt::Key_Hangul_Jamo, "Hangul_Jamo"},
{Qt::Key_Hangul_Romaja, "Hangul_Romaja"},
{Qt::Key_Hangul_Jeonja, "Hangul_Jeonja"},
{Qt::Key_Hangul_Banja, "Hangul_Banja"},
{Qt::Key_Hangul_PreHanja, "Hangul_PreHanja"},
{Qt::Key_Hangul_PostHanja, "Hangul_PostHanja"},
{Qt::Key_Hangul_Special, "Hangul_Special"},
{Qt::Key_Dead_Grave, "Dead_Grave"},
{Qt::Key_Dead_Acute, "Dead_Acute"},
{Qt::Key_Dead_Circumflex, "Dead_Circumflex"},
{Qt::Key_Dead_Tilde, "Dead_Tilde"},
{Qt::Key_Dead_Macron, "Dead_Macron"},
{Qt::Key_Dead_Breve, "Dead_Breve"},
{Qt::Key_Dead_Abovedot, "Dead_Abovedot"},
{Qt::Key_Dead_Diaeresis, "Dead_Diaeresis"},
{Qt::Key_Dead_Abovering, "Dead_Abovering"},
{Qt::Key_Dead_Doubleacute, "Dead_Doubleacute"},
{Qt::Key_Dead_Caron, "Dead_Caron"},
{Qt::Key_Dead_Cedilla, "Dead_Cedilla"},
{Qt::Key_Dead_Ogonek, "Dead_Ogonek"},
{Qt::Key_Dead_Iota, "Dead_Iota"},
{Qt::Key_Dead_Voiced_Sound, "Dead_Voiced_Sound"},
{Qt::Key_Dead_Semivoiced_Sound, "Dead_Semivoiced_Sound"},
{Qt::Key_Dead_Belowdot, "Dead_Belowdot"},
{Qt::Key_Dead_Hook, "Dead_Hook"},
{Qt::Key_Dead_Horn, "Dead_Horn"},
{Qt::Key_Back, "Back"},
{Qt::Key_Forward, "Forward"},
{Qt::Key_Stop, "Stop"},
{Qt::Key_Refresh, "Refresh"},
{Qt::Key_VolumeDown, "VolumeDown"},
{Qt::Key_VolumeMute, "VolumeMute"},
{Qt::Key_VolumeUp, "VolumeUp"},
{Qt::Key_BassBoost, "BassBoost"},
{Qt::Key_BassUp, "BassUp"},
{Qt::Key_BassDown, "BassDown"},
{Qt::Key_TrebleUp, "TrebleUp"},
{Qt::Key_TrebleDown, "TrebleDown"},
{Qt::Key_MediaPlay, "MediaPlay"},
{Qt::Key_MediaStop, "MediaStop"},
{Qt::Key_MediaPrevious, "MediaPrevious"},
{Qt::Key_MediaNext, "MediaNext"},
{Qt::Key_MediaRecord, "MediaRecord"},
{Qt::Key_MediaPause, "MediaPause"},
{Qt::Key_MediaTogglePlayPause, "MediaTogglePlayPause"},
{Qt::Key_HomePage, "HomePage"},
{Qt::Key_Favorites, "Favorites"},
{Qt::Key_Search, "Search"},
{Qt::Key_Standby, "Standby"},
{Qt::Key_OpenUrl, "OpenUrl"},
{Qt::Key_LaunchMail, "LaunchMail"},
{Qt::Key_LaunchMedia, "LaunchMedia"},
{Qt::Key_Launch0, "Launch0"},
{Qt::Key_Launch1, "Launch1"},
{Qt::Key_Launch2, "Launch2"},
{Qt::Key_Launch3, "Launch3"},
{Qt::Key_Launch4, "Launch4"},
{Qt::Key_Launch5, "Launch5"},
{Qt::Key_Launch6, "Launch6"},
{Qt::Key_Launch7, "Launch7"},
{Qt::Key_Launch8, "Launch8"},
{Qt::Key_Launch9, "Launch9"},
{Qt::Key_LaunchA, "LaunchA"},
{Qt::Key_LaunchB, "LaunchB"},
{Qt::Key_LaunchC, "LaunchC"},
{Qt::Key_LaunchD, "LaunchD"},
{Qt::Key_LaunchE, "LaunchE"},
{Qt::Key_LaunchF, "LaunchF"},
{Qt::Key_MonBrightnessUp, "MonBrightnessUp"},
{Qt::Key_MonBrightnessDown, "MonBrightnessDown"},
{Qt::Key_KeyboardLightOnOff, "KeyboardLightOnOff"},
{Qt::Key_KeyboardBrightnessUp, "KeyboardBrightnessUp"},
{Qt::Key_KeyboardBrightnessDown, "KeyboardBrightnessDown"},
{Qt::Key_PowerOff, "PowerOff"},
{Qt::Key_WakeUp, "WakeUp"},
{Qt::Key_Eject, "Eject"},
{Qt::Key_ScreenSaver, "ScreenSaver"},
{Qt::Key_WWW, "WWW"},
{Qt::Key_Memo, "Memo"},
{Qt::Key_LightBulb, "LightBulb"},
{Qt::Key_Shop, "Shop"},
{Qt::Key_History, "History"},
{Qt::Key_AddFavorite, "AddFavorite"},
{Qt::Key_HotLinks, "HotLinks"},
{Qt::Key_BrightnessAdjust, "BrightnessAdjust"},
{Qt::Key_Finance, "Finance"},
{Qt::Key_Community, "Community"},
{Qt::Key_AudioRewind, "AudioRewind"},
{Qt::Key_BackForward, "BackForward"},
{Qt::Key_ApplicationLeft, "ApplicationLeft"},
{Qt::Key_ApplicationRight, "ApplicationRight"},
{Qt::Key_Book, "Book"},
{Qt::Key_CD, "CD"},
{Qt::Key_Calculator, "Calculator"},
{Qt::Key_ToDoList, "ToDoList"},
{Qt::Key_ClearGrab, "ClearGrab"},
{Qt::Key_Close, "Close"},
{Qt::Key_Copy, "Copy"},
{Qt::Key_Cut, "Cut"},
{Qt::Key_Display, "Display"},
{Qt::Key_DOS, "DOS"},
{Qt::Key_Documents, "Documents"},
{Qt::Key_Excel, "Excel"},
{Qt::Key_Explorer, "Explorer"},
{Qt::Key_Game, "Game"},
{Qt::Key_Go, "Go"},
{Qt::Key_iTouch, "iTouch"},
{Qt::Key_LogOff, "LogOff"},
{Qt::Key_Market, "Market"},
{Qt::Key_Meeting, "Meeting"},
{Qt::Key_MenuKB, "MenuKB"},
{Qt::Key_MenuPB, "MenuPB"},
{Qt::Key_MySites, "MySites"},
{Qt::Key_News, "News"},
{Qt::Key_OfficeHome, "OfficeHome"},
{Qt::Key_Option, "Option"},
{Qt::Key_Paste, "Paste"},
{Qt::Key_Phone, "Phone"},
{Qt::Key_Calendar, "Calendar"},
{Qt::Key_Reply, "Reply"},
{Qt::Key_Reload, "Reload"},
{Qt::Key_RotateWindows, "RotateWindows"},
{Qt::Key_RotationPB, "RotationPB"},
{Qt::Key_RotationKB, "RotationKB"},
{Qt::Key_Save, "Save"},
{Qt::Key_Send, "Send"},
{Qt::Key_Spell, "Spell"},
{Qt::Key_SplitScreen, "SplitScreen"},
{Qt::Key_Support, "Support"},
{Qt::Key_TaskPane, "TaskPane"},
{Qt::Key_Terminal, "Terminal"},
{Qt::Key_Tools, "Tools"},
{Qt::Key_Travel, "Travel"},
{Qt::Key_Video, "Video"},
{Qt::Key_Word, "Word"},
{Qt::Key_Xfer, "Xfer"},
{Qt::Key_ZoomIn, "ZoomIn"},
{Qt::Key_ZoomOut, "ZoomOut"},
{Qt::Key_Away, "Away"},
{Qt::Key_Messenger, "Messenger"},
{Qt::Key_WebCam, "WebCam"},
{Qt::Key_MailForward, "MailForward"},
{Qt::Key_Pictures, "Pictures"},
{Qt::Key_Music, "Music"},
{Qt::Key_Battery, "Battery"},
{Qt::Key_Bluetooth, "Bluetooth"},
{Qt::Key_WLAN, "WLAN"},
{Qt::Key_UWB, "UWB"},
{Qt::Key_AudioForward, "AudioForward"},
{Qt::Key_AudioRepeat, "AudioRepeat"},
{Qt::Key_AudioRandomPlay, "AudioRandomPlay"},
{Qt::Key_Subtitle, "Subtitle"},
{Qt::Key_AudioCycleTrack, "AudioCycleTrack"},
{Qt::Key_Time, "Time"},
{Qt::Key_Hibernate, "Hibernate"},
{Qt::Key_View, "View"},
{Qt::Key_TopMenu, "TopMenu"},
{Qt::Key_PowerDown, "PowerDown"},
{Qt::Key_Suspend, "Suspend"},
{Qt::Key_ContrastAdjust, "ContrastAdjust"},
{Qt::Key_LaunchG, "LaunchG"},
{Qt::Key_LaunchH, "LaunchH"},
{Qt::Key_TouchpadToggle, "TouchpadToggle"},
{Qt::Key_TouchpadOn, "TouchpadOn"},
{Qt::Key_TouchpadOff, "TouchpadOff"},
{Qt::Key_MicMute, "MicMute"},
{Qt::Key_Red, "Red"},
{Qt::Key_Green, "Green"},
{Qt::Key_Yellow, "Yellow"},
{Qt::Key_Blue, "Blue"},
{Qt::Key_ChannelUp, "ChannelUp"},
{Qt::Key_ChannelDown, "ChannelDown"},
{Qt::Key_Guide, "Guide"},
{Qt::Key_Info, "Info"},
{Qt::Key_Settings, "Settings"},
{Qt::Key_MicVolumeUp, "MicVolumeUp"},
{Qt::Key_MicVolumeDown, "MicVolumeDown"},
{Qt::Key_New, "New"},
{Qt::Key_Open, "Open"},
{Qt::Key_Find, "Find"},
{Qt::Key_Undo, "Undo"},
{Qt::Key_Redo, "Redo"},
{Qt::Key_MediaLast, "MediaLast"},
{Qt::Key_Select, "Select"},
{Qt::Key_Yes, "Yes"},
{Qt::Key_No, "No"},
{Qt::Key_Cancel, "Cancel"},
{Qt::Key_Printer, "Printer"},
{Qt::Key_Execute, "Execute"},
{Qt::Key_Sleep, "Sleep"},
{Qt::Key_Play, "Play"},
{Qt::Key_Zoom, "Zoom"},
{Qt::Key_Exit, "Exit"},
{Qt::Key_Context1, "Context1"},
{Qt::Key_Context2, "Context2"},
{Qt::Key_Context3, "Context3"},
{Qt::Key_Context4, "Context4"},
{Qt::Key_Call, "Call"},
{Qt::Key_Hangup, "Hangup"},
{Qt::Key_Flip, "Flip"},
{Qt::Key_ToggleCallHangup, "ToggleCallHangup"},
{Qt::Key_VoiceDial, "VoiceDial"},
{Qt::Key_LastNumberRedial, "LastNumberRedial"},
{Qt::Key_Camera, "Camera"},
{Qt::Key_CameraFocus, "CameraFocus"}};
std::optional<u32> InputManager::ConvertHostKeyboardStringToCode(const std::string_view& str)
{
for (const KeyCodeName& name : s_qt_key_names)
{
if (str == name.name)
return static_cast<u32>(name.code);
}
return std::nullopt;
}
std::optional<std::string> InputManager::ConvertHostKeyboardCodeToString(u32 code)
{
for (const KeyCodeName& name : s_qt_key_names)
{
if (static_cast<int>(code) == name.code)
return std::string(name.name);
}
return std::nullopt;
}

703
pcsx2-qt/QtUtils.cpp Normal file
View File

@ -0,0 +1,703 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QMetaObject>
#include <QtGui/QDesktopServices>
#include <QtGui/QKeyEvent>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QtGui/QAction>
#else
#include <QtWidgets/QAction>
#endif
#include <QtWidgets/QComboBox>
#include <QtWidgets/QDialog>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QScrollBar>
#include <QtWidgets/QStyle>
#include <QtWidgets/QTableView>
#include <QtWidgets/QTreeView>
#include <algorithm>
#include <array>
#include <map>
#include "QtUtils.h"
namespace QtUtils
{
void MarkActionAsDefault(QAction* action)
{
QFont new_font(action->font());
new_font.setBold(true);
action->setFont(new_font);
}
QFrame* CreateHorizontalLine(QWidget* parent)
{
QFrame* line = new QFrame(parent);
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
return line;
}
QWidget* GetRootWidget(QWidget* widget, bool stop_at_window_or_dialog)
{
QWidget* next_parent = widget->parentWidget();
while (next_parent)
{
if (stop_at_window_or_dialog && (widget->metaObject()->inherits(&QMainWindow::staticMetaObject) ||
widget->metaObject()->inherits(&QDialog::staticMetaObject)))
{
break;
}
widget = next_parent;
next_parent = widget->parentWidget();
}
return widget;
}
template <typename T>
static void ResizeColumnsForView(T* view, const std::initializer_list<int>& widths)
{
QHeaderView* header;
if constexpr (std::is_same_v<T, QTableView>)
header = view->horizontalHeader();
else
header = view->header();
const int min_column_width = header->minimumSectionSize();
const int scrollbar_width = ((view->verticalScrollBar() && view->verticalScrollBar()->isVisible()) ||
view->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) ?
view->verticalScrollBar()->width() :
0;
int num_flex_items = 0;
int total_width = 0;
int column_index = 0;
for (const int spec_width : widths)
{
if (!view->isColumnHidden(column_index))
{
if (spec_width < 0)
num_flex_items++;
else
total_width += std::max(spec_width, min_column_width);
}
column_index++;
}
const int flex_width =
(num_flex_items > 0) ?
std::max((view->contentsRect().width() - total_width - scrollbar_width) / num_flex_items, 1) :
0;
column_index = 0;
for (const int spec_width : widths)
{
if (view->isColumnHidden(column_index))
{
column_index++;
continue;
}
const int width = spec_width < 0 ? flex_width : (std::max(spec_width, min_column_width));
view->setColumnWidth(column_index, width);
column_index++;
}
}
void ResizeColumnsForTableView(QTableView* view, const std::initializer_list<int>& widths)
{
ResizeColumnsForView(view, widths);
}
void ResizeColumnsForTreeView(QTreeView* view, const std::initializer_list<int>& widths)
{
ResizeColumnsForView(view, widths);
}
static const std::map<int, QString> s_qt_key_names = {
{Qt::Key_Escape, QStringLiteral("Escape")},
{Qt::Key_Tab, QStringLiteral("Tab")},
{Qt::Key_Backtab, QStringLiteral("Backtab")},
{Qt::Key_Backspace, QStringLiteral("Backspace")},
{Qt::Key_Return, QStringLiteral("Return")},
{Qt::Key_Enter, QStringLiteral("Enter")},
{Qt::Key_Insert, QStringLiteral("Insert")},
{Qt::Key_Delete, QStringLiteral("Delete")},
{Qt::Key_Pause, QStringLiteral("Pause")},
{Qt::Key_Print, QStringLiteral("Print")},
{Qt::Key_SysReq, QStringLiteral("SysReq")},
{Qt::Key_Clear, QStringLiteral("Clear")},
{Qt::Key_Home, QStringLiteral("Home")},
{Qt::Key_End, QStringLiteral("End")},
{Qt::Key_Left, QStringLiteral("Left")},
{Qt::Key_Up, QStringLiteral("Up")},
{Qt::Key_Right, QStringLiteral("Right")},
{Qt::Key_Down, QStringLiteral("Down")},
{Qt::Key_PageUp, QStringLiteral("PageUp")},
{Qt::Key_PageDown, QStringLiteral("PageDown")},
{Qt::Key_Shift, QStringLiteral("Shift")},
{Qt::Key_Control, QStringLiteral("Control")},
{Qt::Key_Meta, QStringLiteral("Meta")},
{Qt::Key_Alt, QStringLiteral("Alt")},
{Qt::Key_CapsLock, QStringLiteral("CapsLock")},
{Qt::Key_NumLock, QStringLiteral("NumLock")},
{Qt::Key_ScrollLock, QStringLiteral("ScrollLock")},
{Qt::Key_F1, QStringLiteral("F1")},
{Qt::Key_F2, QStringLiteral("F2")},
{Qt::Key_F3, QStringLiteral("F3")},
{Qt::Key_F4, QStringLiteral("F4")},
{Qt::Key_F5, QStringLiteral("F5")},
{Qt::Key_F6, QStringLiteral("F6")},
{Qt::Key_F7, QStringLiteral("F7")},
{Qt::Key_F8, QStringLiteral("F8")},
{Qt::Key_F9, QStringLiteral("F9")},
{Qt::Key_F10, QStringLiteral("F10")},
{Qt::Key_F11, QStringLiteral("F11")},
{Qt::Key_F12, QStringLiteral("F12")},
{Qt::Key_F13, QStringLiteral("F13")},
{Qt::Key_F14, QStringLiteral("F14")},
{Qt::Key_F15, QStringLiteral("F15")},
{Qt::Key_F16, QStringLiteral("F16")},
{Qt::Key_F17, QStringLiteral("F17")},
{Qt::Key_F18, QStringLiteral("F18")},
{Qt::Key_F19, QStringLiteral("F19")},
{Qt::Key_F20, QStringLiteral("F20")},
{Qt::Key_F21, QStringLiteral("F21")},
{Qt::Key_F22, QStringLiteral("F22")},
{Qt::Key_F23, QStringLiteral("F23")},
{Qt::Key_F24, QStringLiteral("F24")},
{Qt::Key_F25, QStringLiteral("F25")},
{Qt::Key_F26, QStringLiteral("F26")},
{Qt::Key_F27, QStringLiteral("F27")},
{Qt::Key_F28, QStringLiteral("F28")},
{Qt::Key_F29, QStringLiteral("F29")},
{Qt::Key_F30, QStringLiteral("F30")},
{Qt::Key_F31, QStringLiteral("F31")},
{Qt::Key_F32, QStringLiteral("F32")},
{Qt::Key_F33, QStringLiteral("F33")},
{Qt::Key_F34, QStringLiteral("F34")},
{Qt::Key_F35, QStringLiteral("F35")},
{Qt::Key_Super_L, QStringLiteral("Super_L")},
{Qt::Key_Super_R, QStringLiteral("Super_R")},
{Qt::Key_Menu, QStringLiteral("Menu")},
{Qt::Key_Hyper_L, QStringLiteral("Hyper_L")},
{Qt::Key_Hyper_R, QStringLiteral("Hyper_R")},
{Qt::Key_Help, QStringLiteral("Help")},
{Qt::Key_Direction_L, QStringLiteral("Direction_L")},
{Qt::Key_Direction_R, QStringLiteral("Direction_R")},
{Qt::Key_Space, QStringLiteral("Space")},
{Qt::Key_Any, QStringLiteral("Any")},
{Qt::Key_Exclam, QStringLiteral("Exclam")},
{Qt::Key_QuoteDbl, QStringLiteral("QuoteDbl")},
{Qt::Key_NumberSign, QStringLiteral("NumberSign")},
{Qt::Key_Dollar, QStringLiteral("Dollar")},
{Qt::Key_Percent, QStringLiteral("Percent")},
{Qt::Key_Ampersand, QStringLiteral("Ampersand")},
{Qt::Key_Apostrophe, QStringLiteral("Apostrophe")},
{Qt::Key_ParenLeft, QStringLiteral("ParenLeft")},
{Qt::Key_ParenRight, QStringLiteral("ParenRight")},
{Qt::Key_Asterisk, QStringLiteral("Asterisk")},
{Qt::Key_Plus, QStringLiteral("Plus")},
{Qt::Key_Comma, QStringLiteral("Comma")},
{Qt::Key_Minus, QStringLiteral("Minus")},
{Qt::Key_Period, QStringLiteral("Period")},
{Qt::Key_Slash, QStringLiteral("Slash")},
{Qt::Key_0, QStringLiteral("0")},
{Qt::Key_1, QStringLiteral("1")},
{Qt::Key_2, QStringLiteral("2")},
{Qt::Key_3, QStringLiteral("3")},
{Qt::Key_4, QStringLiteral("4")},
{Qt::Key_5, QStringLiteral("5")},
{Qt::Key_6, QStringLiteral("6")},
{Qt::Key_7, QStringLiteral("7")},
{Qt::Key_8, QStringLiteral("8")},
{Qt::Key_9, QStringLiteral("9")},
{Qt::Key_Colon, QStringLiteral("Colon")},
{Qt::Key_Semicolon, QStringLiteral("Semicolon")},
{Qt::Key_Less, QStringLiteral("Less")},
{Qt::Key_Equal, QStringLiteral("Equal")},
{Qt::Key_Greater, QStringLiteral("Greater")},
{Qt::Key_Question, QStringLiteral("Question")},
{Qt::Key_At, QStringLiteral("At")},
{Qt::Key_A, QStringLiteral("A")},
{Qt::Key_B, QStringLiteral("B")},
{Qt::Key_C, QStringLiteral("C")},
{Qt::Key_D, QStringLiteral("D")},
{Qt::Key_E, QStringLiteral("E")},
{Qt::Key_F, QStringLiteral("F")},
{Qt::Key_G, QStringLiteral("G")},
{Qt::Key_H, QStringLiteral("H")},
{Qt::Key_I, QStringLiteral("I")},
{Qt::Key_J, QStringLiteral("J")},
{Qt::Key_K, QStringLiteral("K")},
{Qt::Key_L, QStringLiteral("L")},
{Qt::Key_M, QStringLiteral("M")},
{Qt::Key_N, QStringLiteral("N")},
{Qt::Key_O, QStringLiteral("O")},
{Qt::Key_P, QStringLiteral("P")},
{Qt::Key_Q, QStringLiteral("Q")},
{Qt::Key_R, QStringLiteral("R")},
{Qt::Key_S, QStringLiteral("S")},
{Qt::Key_T, QStringLiteral("T")},
{Qt::Key_U, QStringLiteral("U")},
{Qt::Key_V, QStringLiteral("V")},
{Qt::Key_W, QStringLiteral("W")},
{Qt::Key_X, QStringLiteral("X")},
{Qt::Key_Y, QStringLiteral("Y")},
{Qt::Key_Z, QStringLiteral("Z")},
{Qt::Key_BracketLeft, QStringLiteral("BracketLeft")},
{Qt::Key_Backslash, QStringLiteral("Backslash")},
{Qt::Key_BracketRight, QStringLiteral("BracketRight")},
{Qt::Key_AsciiCircum, QStringLiteral("AsciiCircum")},
{Qt::Key_Underscore, QStringLiteral("Underscore")},
{Qt::Key_QuoteLeft, QStringLiteral("QuoteLeft")},
{Qt::Key_BraceLeft, QStringLiteral("BraceLeft")},
{Qt::Key_Bar, QStringLiteral("Bar")},
{Qt::Key_BraceRight, QStringLiteral("BraceRight")},
{Qt::Key_AsciiTilde, QStringLiteral("AsciiTilde")},
{Qt::Key_nobreakspace, QStringLiteral("nobreakspace")},
{Qt::Key_exclamdown, QStringLiteral("exclamdown")},
{Qt::Key_cent, QStringLiteral("cent")},
{Qt::Key_sterling, QStringLiteral("sterling")},
{Qt::Key_currency, QStringLiteral("currency")},
{Qt::Key_yen, QStringLiteral("yen")},
{Qt::Key_brokenbar, QStringLiteral("brokenbar")},
{Qt::Key_section, QStringLiteral("section")},
{Qt::Key_diaeresis, QStringLiteral("diaeresis")},
{Qt::Key_copyright, QStringLiteral("copyright")},
{Qt::Key_ordfeminine, QStringLiteral("ordfeminine")},
{Qt::Key_guillemotleft, QStringLiteral("guillemotleft")},
{Qt::Key_notsign, QStringLiteral("notsign")},
{Qt::Key_hyphen, QStringLiteral("hyphen")},
{Qt::Key_registered, QStringLiteral("registered")},
{Qt::Key_macron, QStringLiteral("macron")},
{Qt::Key_degree, QStringLiteral("degree")},
{Qt::Key_plusminus, QStringLiteral("plusminus")},
{Qt::Key_twosuperior, QStringLiteral("twosuperior")},
{Qt::Key_threesuperior, QStringLiteral("threesuperior")},
{Qt::Key_acute, QStringLiteral("acute")},
{Qt::Key_mu, QStringLiteral("mu")},
{Qt::Key_paragraph, QStringLiteral("paragraph")},
{Qt::Key_periodcentered, QStringLiteral("periodcentered")},
{Qt::Key_cedilla, QStringLiteral("cedilla")},
{Qt::Key_onesuperior, QStringLiteral("onesuperior")},
{Qt::Key_masculine, QStringLiteral("masculine")},
{Qt::Key_guillemotright, QStringLiteral("guillemotright")},
{Qt::Key_onequarter, QStringLiteral("onequarter")},
{Qt::Key_onehalf, QStringLiteral("onehalf")},
{Qt::Key_threequarters, QStringLiteral("threequarters")},
{Qt::Key_questiondown, QStringLiteral("questiondown")},
{Qt::Key_Agrave, QStringLiteral("Agrave")},
{Qt::Key_Aacute, QStringLiteral("Aacute")},
{Qt::Key_Acircumflex, QStringLiteral("Acircumflex")},
{Qt::Key_Atilde, QStringLiteral("Atilde")},
{Qt::Key_Adiaeresis, QStringLiteral("Adiaeresis")},
{Qt::Key_Aring, QStringLiteral("Aring")},
{Qt::Key_AE, QStringLiteral("AE")},
{Qt::Key_Ccedilla, QStringLiteral("Ccedilla")},
{Qt::Key_Egrave, QStringLiteral("Egrave")},
{Qt::Key_Eacute, QStringLiteral("Eacute")},
{Qt::Key_Ecircumflex, QStringLiteral("Ecircumflex")},
{Qt::Key_Ediaeresis, QStringLiteral("Ediaeresis")},
{Qt::Key_Igrave, QStringLiteral("Igrave")},
{Qt::Key_Iacute, QStringLiteral("Iacute")},
{Qt::Key_Icircumflex, QStringLiteral("Icircumflex")},
{Qt::Key_Idiaeresis, QStringLiteral("Idiaeresis")},
{Qt::Key_ETH, QStringLiteral("ETH")},
{Qt::Key_Ntilde, QStringLiteral("Ntilde")},
{Qt::Key_Ograve, QStringLiteral("Ograve")},
{Qt::Key_Oacute, QStringLiteral("Oacute")},
{Qt::Key_Ocircumflex, QStringLiteral("Ocircumflex")},
{Qt::Key_Otilde, QStringLiteral("Otilde")},
{Qt::Key_Odiaeresis, QStringLiteral("Odiaeresis")},
{Qt::Key_multiply, QStringLiteral("multiply")},
{Qt::Key_Ooblique, QStringLiteral("Ooblique")},
{Qt::Key_Ugrave, QStringLiteral("Ugrave")},
{Qt::Key_Uacute, QStringLiteral("Uacute")},
{Qt::Key_Ucircumflex, QStringLiteral("Ucircumflex")},
{Qt::Key_Udiaeresis, QStringLiteral("Udiaeresis")},
{Qt::Key_Yacute, QStringLiteral("Yacute")},
{Qt::Key_THORN, QStringLiteral("THORN")},
{Qt::Key_ssharp, QStringLiteral("ssharp")},
{Qt::Key_division, QStringLiteral("division")},
{Qt::Key_ydiaeresis, QStringLiteral("ydiaeresis")},
{Qt::Key_AltGr, QStringLiteral("AltGr")},
{Qt::Key_Multi_key, QStringLiteral("Multi_key")},
{Qt::Key_Codeinput, QStringLiteral("Codeinput")},
{Qt::Key_SingleCandidate, QStringLiteral("SingleCandidate")},
{Qt::Key_MultipleCandidate, QStringLiteral("MultipleCandidate")},
{Qt::Key_PreviousCandidate, QStringLiteral("PreviousCandidate")},
{Qt::Key_Mode_switch, QStringLiteral("Mode_switch")},
{Qt::Key_Kanji, QStringLiteral("Kanji")},
{Qt::Key_Muhenkan, QStringLiteral("Muhenkan")},
{Qt::Key_Henkan, QStringLiteral("Henkan")},
{Qt::Key_Romaji, QStringLiteral("Romaji")},
{Qt::Key_Hiragana, QStringLiteral("Hiragana")},
{Qt::Key_Katakana, QStringLiteral("Katakana")},
{Qt::Key_Hiragana_Katakana, QStringLiteral("Hiragana_Katakana")},
{Qt::Key_Zenkaku, QStringLiteral("Zenkaku")},
{Qt::Key_Hankaku, QStringLiteral("Hankaku")},
{Qt::Key_Zenkaku_Hankaku, QStringLiteral("Zenkaku_Hankaku")},
{Qt::Key_Touroku, QStringLiteral("Touroku")},
{Qt::Key_Massyo, QStringLiteral("Massyo")},
{Qt::Key_Kana_Lock, QStringLiteral("Kana_Lock")},
{Qt::Key_Kana_Shift, QStringLiteral("Kana_Shift")},
{Qt::Key_Eisu_Shift, QStringLiteral("Eisu_Shift")},
{Qt::Key_Eisu_toggle, QStringLiteral("Eisu_toggle")},
{Qt::Key_Hangul, QStringLiteral("Hangul")},
{Qt::Key_Hangul_Start, QStringLiteral("Hangul_Start")},
{Qt::Key_Hangul_End, QStringLiteral("Hangul_End")},
{Qt::Key_Hangul_Hanja, QStringLiteral("Hangul_Hanja")},
{Qt::Key_Hangul_Jamo, QStringLiteral("Hangul_Jamo")},
{Qt::Key_Hangul_Romaja, QStringLiteral("Hangul_Romaja")},
{Qt::Key_Hangul_Jeonja, QStringLiteral("Hangul_Jeonja")},
{Qt::Key_Hangul_Banja, QStringLiteral("Hangul_Banja")},
{Qt::Key_Hangul_PreHanja, QStringLiteral("Hangul_PreHanja")},
{Qt::Key_Hangul_PostHanja, QStringLiteral("Hangul_PostHanja")},
{Qt::Key_Hangul_Special, QStringLiteral("Hangul_Special")},
{Qt::Key_Dead_Grave, QStringLiteral("Dead_Grave")},
{Qt::Key_Dead_Acute, QStringLiteral("Dead_Acute")},
{Qt::Key_Dead_Circumflex, QStringLiteral("Dead_Circumflex")},
{Qt::Key_Dead_Tilde, QStringLiteral("Dead_Tilde")},
{Qt::Key_Dead_Macron, QStringLiteral("Dead_Macron")},
{Qt::Key_Dead_Breve, QStringLiteral("Dead_Breve")},
{Qt::Key_Dead_Abovedot, QStringLiteral("Dead_Abovedot")},
{Qt::Key_Dead_Diaeresis, QStringLiteral("Dead_Diaeresis")},
{Qt::Key_Dead_Abovering, QStringLiteral("Dead_Abovering")},
{Qt::Key_Dead_Doubleacute, QStringLiteral("Dead_Doubleacute")},
{Qt::Key_Dead_Caron, QStringLiteral("Dead_Caron")},
{Qt::Key_Dead_Cedilla, QStringLiteral("Dead_Cedilla")},
{Qt::Key_Dead_Ogonek, QStringLiteral("Dead_Ogonek")},
{Qt::Key_Dead_Iota, QStringLiteral("Dead_Iota")},
{Qt::Key_Dead_Voiced_Sound, QStringLiteral("Dead_Voiced_Sound")},
{Qt::Key_Dead_Semivoiced_Sound, QStringLiteral("Dead_Semivoiced_Sound")},
{Qt::Key_Dead_Belowdot, QStringLiteral("Dead_Belowdot")},
{Qt::Key_Dead_Hook, QStringLiteral("Dead_Hook")},
{Qt::Key_Dead_Horn, QStringLiteral("Dead_Horn")},
{Qt::Key_Back, QStringLiteral("Back")},
{Qt::Key_Forward, QStringLiteral("Forward")},
{Qt::Key_Stop, QStringLiteral("Stop")},
{Qt::Key_Refresh, QStringLiteral("Refresh")},
{Qt::Key_VolumeDown, QStringLiteral("VolumeDown")},
{Qt::Key_VolumeMute, QStringLiteral("VolumeMute")},
{Qt::Key_VolumeUp, QStringLiteral("VolumeUp")},
{Qt::Key_BassBoost, QStringLiteral("BassBoost")},
{Qt::Key_BassUp, QStringLiteral("BassUp")},
{Qt::Key_BassDown, QStringLiteral("BassDown")},
{Qt::Key_TrebleUp, QStringLiteral("TrebleUp")},
{Qt::Key_TrebleDown, QStringLiteral("TrebleDown")},
{Qt::Key_MediaPlay, QStringLiteral("MediaPlay")},
{Qt::Key_MediaStop, QStringLiteral("MediaStop")},
{Qt::Key_MediaPrevious, QStringLiteral("MediaPrevious")},
{Qt::Key_MediaNext, QStringLiteral("MediaNext")},
{Qt::Key_MediaRecord, QStringLiteral("MediaRecord")},
{Qt::Key_MediaPause, QStringLiteral("MediaPause")},
{Qt::Key_MediaTogglePlayPause, QStringLiteral("MediaTogglePlayPause")},
{Qt::Key_HomePage, QStringLiteral("HomePage")},
{Qt::Key_Favorites, QStringLiteral("Favorites")},
{Qt::Key_Search, QStringLiteral("Search")},
{Qt::Key_Standby, QStringLiteral("Standby")},
{Qt::Key_OpenUrl, QStringLiteral("OpenUrl")},
{Qt::Key_LaunchMail, QStringLiteral("LaunchMail")},
{Qt::Key_LaunchMedia, QStringLiteral("LaunchMedia")},
{Qt::Key_Launch0, QStringLiteral("Launch0")},
{Qt::Key_Launch1, QStringLiteral("Launch1")},
{Qt::Key_Launch2, QStringLiteral("Launch2")},
{Qt::Key_Launch3, QStringLiteral("Launch3")},
{Qt::Key_Launch4, QStringLiteral("Launch4")},
{Qt::Key_Launch5, QStringLiteral("Launch5")},
{Qt::Key_Launch6, QStringLiteral("Launch6")},
{Qt::Key_Launch7, QStringLiteral("Launch7")},
{Qt::Key_Launch8, QStringLiteral("Launch8")},
{Qt::Key_Launch9, QStringLiteral("Launch9")},
{Qt::Key_LaunchA, QStringLiteral("LaunchA")},
{Qt::Key_LaunchB, QStringLiteral("LaunchB")},
{Qt::Key_LaunchC, QStringLiteral("LaunchC")},
{Qt::Key_LaunchD, QStringLiteral("LaunchD")},
{Qt::Key_LaunchE, QStringLiteral("LaunchE")},
{Qt::Key_LaunchF, QStringLiteral("LaunchF")},
{Qt::Key_MonBrightnessUp, QStringLiteral("MonBrightnessUp")},
{Qt::Key_MonBrightnessDown, QStringLiteral("MonBrightnessDown")},
{Qt::Key_KeyboardLightOnOff, QStringLiteral("KeyboardLightOnOff")},
{Qt::Key_KeyboardBrightnessUp, QStringLiteral("KeyboardBrightnessUp")},
{Qt::Key_KeyboardBrightnessDown, QStringLiteral("KeyboardBrightnessDown")},
{Qt::Key_PowerOff, QStringLiteral("PowerOff")},
{Qt::Key_WakeUp, QStringLiteral("WakeUp")},
{Qt::Key_Eject, QStringLiteral("Eject")},
{Qt::Key_ScreenSaver, QStringLiteral("ScreenSaver")},
{Qt::Key_WWW, QStringLiteral("WWW")},
{Qt::Key_Memo, QStringLiteral("Memo")},
{Qt::Key_LightBulb, QStringLiteral("LightBulb")},
{Qt::Key_Shop, QStringLiteral("Shop")},
{Qt::Key_History, QStringLiteral("History")},
{Qt::Key_AddFavorite, QStringLiteral("AddFavorite")},
{Qt::Key_HotLinks, QStringLiteral("HotLinks")},
{Qt::Key_BrightnessAdjust, QStringLiteral("BrightnessAdjust")},
{Qt::Key_Finance, QStringLiteral("Finance")},
{Qt::Key_Community, QStringLiteral("Community")},
{Qt::Key_AudioRewind, QStringLiteral("AudioRewind")},
{Qt::Key_BackForward, QStringLiteral("BackForward")},
{Qt::Key_ApplicationLeft, QStringLiteral("ApplicationLeft")},
{Qt::Key_ApplicationRight, QStringLiteral("ApplicationRight")},
{Qt::Key_Book, QStringLiteral("Book")},
{Qt::Key_CD, QStringLiteral("CD")},
{Qt::Key_Calculator, QStringLiteral("Calculator")},
{Qt::Key_ToDoList, QStringLiteral("ToDoList")},
{Qt::Key_ClearGrab, QStringLiteral("ClearGrab")},
{Qt::Key_Close, QStringLiteral("Close")},
{Qt::Key_Copy, QStringLiteral("Copy")},
{Qt::Key_Cut, QStringLiteral("Cut")},
{Qt::Key_Display, QStringLiteral("Display")},
{Qt::Key_DOS, QStringLiteral("DOS")},
{Qt::Key_Documents, QStringLiteral("Documents")},
{Qt::Key_Excel, QStringLiteral("Excel")},
{Qt::Key_Explorer, QStringLiteral("Explorer")},
{Qt::Key_Game, QStringLiteral("Game")},
{Qt::Key_Go, QStringLiteral("Go")},
{Qt::Key_iTouch, QStringLiteral("iTouch")},
{Qt::Key_LogOff, QStringLiteral("LogOff")},
{Qt::Key_Market, QStringLiteral("Market")},
{Qt::Key_Meeting, QStringLiteral("Meeting")},
{Qt::Key_MenuKB, QStringLiteral("MenuKB")},
{Qt::Key_MenuPB, QStringLiteral("MenuPB")},
{Qt::Key_MySites, QStringLiteral("MySites")},
{Qt::Key_News, QStringLiteral("News")},
{Qt::Key_OfficeHome, QStringLiteral("OfficeHome")},
{Qt::Key_Option, QStringLiteral("Option")},
{Qt::Key_Paste, QStringLiteral("Paste")},
{Qt::Key_Phone, QStringLiteral("Phone")},
{Qt::Key_Calendar, QStringLiteral("Calendar")},
{Qt::Key_Reply, QStringLiteral("Reply")},
{Qt::Key_Reload, QStringLiteral("Reload")},
{Qt::Key_RotateWindows, QStringLiteral("RotateWindows")},
{Qt::Key_RotationPB, QStringLiteral("RotationPB")},
{Qt::Key_RotationKB, QStringLiteral("RotationKB")},
{Qt::Key_Save, QStringLiteral("Save")},
{Qt::Key_Send, QStringLiteral("Send")},
{Qt::Key_Spell, QStringLiteral("Spell")},
{Qt::Key_SplitScreen, QStringLiteral("SplitScreen")},
{Qt::Key_Support, QStringLiteral("Support")},
{Qt::Key_TaskPane, QStringLiteral("TaskPane")},
{Qt::Key_Terminal, QStringLiteral("Terminal")},
{Qt::Key_Tools, QStringLiteral("Tools")},
{Qt::Key_Travel, QStringLiteral("Travel")},
{Qt::Key_Video, QStringLiteral("Video")},
{Qt::Key_Word, QStringLiteral("Word")},
{Qt::Key_Xfer, QStringLiteral("Xfer")},
{Qt::Key_ZoomIn, QStringLiteral("ZoomIn")},
{Qt::Key_ZoomOut, QStringLiteral("ZoomOut")},
{Qt::Key_Away, QStringLiteral("Away")},
{Qt::Key_Messenger, QStringLiteral("Messenger")},
{Qt::Key_WebCam, QStringLiteral("WebCam")},
{Qt::Key_MailForward, QStringLiteral("MailForward")},
{Qt::Key_Pictures, QStringLiteral("Pictures")},
{Qt::Key_Music, QStringLiteral("Music")},
{Qt::Key_Battery, QStringLiteral("Battery")},
{Qt::Key_Bluetooth, QStringLiteral("Bluetooth")},
{Qt::Key_WLAN, QStringLiteral("WLAN")},
{Qt::Key_UWB, QStringLiteral("UWB")},
{Qt::Key_AudioForward, QStringLiteral("AudioForward")},
{Qt::Key_AudioRepeat, QStringLiteral("AudioRepeat")},
{Qt::Key_AudioRandomPlay, QStringLiteral("AudioRandomPlay")},
{Qt::Key_Subtitle, QStringLiteral("Subtitle")},
{Qt::Key_AudioCycleTrack, QStringLiteral("AudioCycleTrack")},
{Qt::Key_Time, QStringLiteral("Time")},
{Qt::Key_Hibernate, QStringLiteral("Hibernate")},
{Qt::Key_View, QStringLiteral("View")},
{Qt::Key_TopMenu, QStringLiteral("TopMenu")},
{Qt::Key_PowerDown, QStringLiteral("PowerDown")},
{Qt::Key_Suspend, QStringLiteral("Suspend")},
{Qt::Key_ContrastAdjust, QStringLiteral("ContrastAdjust")},
{Qt::Key_LaunchG, QStringLiteral("LaunchG")},
{Qt::Key_LaunchH, QStringLiteral("LaunchH")},
{Qt::Key_TouchpadToggle, QStringLiteral("TouchpadToggle")},
{Qt::Key_TouchpadOn, QStringLiteral("TouchpadOn")},
{Qt::Key_TouchpadOff, QStringLiteral("TouchpadOff")},
{Qt::Key_MicMute, QStringLiteral("MicMute")},
{Qt::Key_Red, QStringLiteral("Red")},
{Qt::Key_Green, QStringLiteral("Green")},
{Qt::Key_Yellow, QStringLiteral("Yellow")},
{Qt::Key_Blue, QStringLiteral("Blue")},
{Qt::Key_ChannelUp, QStringLiteral("ChannelUp")},
{Qt::Key_ChannelDown, QStringLiteral("ChannelDown")},
{Qt::Key_Guide, QStringLiteral("Guide")},
{Qt::Key_Info, QStringLiteral("Info")},
{Qt::Key_Settings, QStringLiteral("Settings")},
{Qt::Key_MicVolumeUp, QStringLiteral("MicVolumeUp")},
{Qt::Key_MicVolumeDown, QStringLiteral("MicVolumeDown")},
{Qt::Key_New, QStringLiteral("New")},
{Qt::Key_Open, QStringLiteral("Open")},
{Qt::Key_Find, QStringLiteral("Find")},
{Qt::Key_Undo, QStringLiteral("Undo")},
{Qt::Key_Redo, QStringLiteral("Redo")},
{Qt::Key_MediaLast, QStringLiteral("MediaLast")},
{Qt::Key_Select, QStringLiteral("Select")},
{Qt::Key_Yes, QStringLiteral("Yes")},
{Qt::Key_No, QStringLiteral("No")},
{Qt::Key_Cancel, QStringLiteral("Cancel")},
{Qt::Key_Printer, QStringLiteral("Printer")},
{Qt::Key_Execute, QStringLiteral("Execute")},
{Qt::Key_Sleep, QStringLiteral("Sleep")},
{Qt::Key_Play, QStringLiteral("Play")},
{Qt::Key_Zoom, QStringLiteral("Zoom")},
{Qt::Key_Exit, QStringLiteral("Exit")},
{Qt::Key_Context1, QStringLiteral("Context1")},
{Qt::Key_Context2, QStringLiteral("Context2")},
{Qt::Key_Context3, QStringLiteral("Context3")},
{Qt::Key_Context4, QStringLiteral("Context4")},
{Qt::Key_Call, QStringLiteral("Call")},
{Qt::Key_Hangup, QStringLiteral("Hangup")},
{Qt::Key_Flip, QStringLiteral("Flip")},
{Qt::Key_ToggleCallHangup, QStringLiteral("ToggleCallHangup")},
{Qt::Key_VoiceDial, QStringLiteral("VoiceDial")},
{Qt::Key_LastNumberRedial, QStringLiteral("LastNumberRedial")},
{Qt::Key_Camera, QStringLiteral("Camera")},
{Qt::Key_CameraFocus, QStringLiteral("CameraFocus")}};
struct QtKeyModifierEntry
{
Qt::KeyboardModifier mod;
Qt::Key key;
QString name;
};
static const std::array<QtKeyModifierEntry, 5> s_qt_key_modifiers = {
{{Qt::ShiftModifier, Qt::Key_Shift, QStringLiteral("Shift")},
{Qt::ControlModifier, Qt::Key_Control, QStringLiteral("Control")},
{Qt::AltModifier, Qt::Key_Alt, QStringLiteral("Alt")},
{Qt::MetaModifier, Qt::Key_Meta, QStringLiteral("Meta")},
{Qt::KeypadModifier, static_cast<Qt::Key>(0), QStringLiteral("Keypad")}}};
QString GetKeyIdentifier(int key)
{
const auto it = s_qt_key_names.find(key);
return it == s_qt_key_names.end() ? QString() : it->second;
}
std::optional<int> GetKeyIdForIdentifier(const QString& key_identifier)
{
for (const auto& it : s_qt_key_names)
{
if (it.second == key_identifier)
return it.first;
}
return std::nullopt;
}
QString KeyEventToString(int key, Qt::KeyboardModifiers mods)
{
QString key_name = GetKeyIdentifier(key);
if (key_name.isEmpty())
return {};
QString ret;
for (const QtKeyModifierEntry& mod : s_qt_key_modifiers)
{
if (mods & mod.mod && key != mod.key)
{
ret.append(mod.name);
ret.append('+');
}
}
ret.append(key_name);
return ret;
}
std::optional<int> ParseKeyString(const QString& key_str)
{
const QStringList sections = key_str.split('+');
std::optional<int> key_id = GetKeyIdForIdentifier(sections.last());
if (!key_id)
return std::nullopt;
int ret = key_id.value();
if (sections.size() > 1)
{
const int num_modifiers = sections.size() - 1;
for (int i = 0; i < num_modifiers; i++)
{
for (const QtKeyModifierEntry& mod : s_qt_key_modifiers)
{
if (sections[i] == mod.name)
{
ret |= static_cast<int>(mod.mod);
break;
}
}
}
}
return ret;
}
int KeyEventToInt(int key, Qt::KeyboardModifiers mods)
{
int val = key;
if (mods != 0)
{
for (const QtKeyModifierEntry& mod : s_qt_key_modifiers)
{
if (mods & mod.mod && key != mod.key)
val |= static_cast<int>(mod.mod);
}
}
return val;
}
void OpenURL(QWidget* parent, const QUrl& qurl)
{
if (!QDesktopServices::openUrl(qurl))
{
QMessageBox::critical(parent, QObject::tr("Failed to open URL"),
QObject::tr("Failed to open URL.\n\nThe URL was: %1").arg(qurl.toString()));
}
}
void OpenURL(QWidget* parent, const char* url)
{
return OpenURL(parent, QUrl::fromEncoded(QByteArray(url, static_cast<int>(std::strlen(url)))));
}
void OpenURL(QWidget* parent, const QString& url)
{
return OpenURL(parent, QUrl(url));
}
wxString QStringToWxString(const QString& str)
{
return wxString(str.toStdWString());
}
QString WxStringToQString(const wxString& str)
{
return QString::fromStdWString(str.ToStdWstring());
}
} // namespace QtUtils

85
pcsx2-qt/QtUtils.h Normal file
View File

@ -0,0 +1,85 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtCore/QByteArray>
#include <QtCore/QMetaType>
#include <QtCore/QString>
#include <functional>
#include <initializer_list>
#include <optional>
Q_DECLARE_METATYPE(std::optional<bool>);
Q_DECLARE_METATYPE(std::function<void()>);
class ByteStream;
class QAction;
class QComboBox;
class QFrame;
class QKeyEvent;
class QTableView;
class QTreeView;
class QVariant;
class QWidget;
class QUrl;
// TODO: Get rid of wx interoperability later on.
#include <wx/string.h>
namespace QtUtils
{
/// Marks an action as the "default" - i.e. makes the text bold.
void MarkActionAsDefault(QAction* action);
/// Creates a horizontal line widget.
QFrame* CreateHorizontalLine(QWidget* parent);
/// Returns the greatest parent of a widget, i.e. its dialog/window.
QWidget* GetRootWidget(QWidget* widget, bool stop_at_window_or_dialog = true);
/// Resizes columns of the table view to at the specified widths. A negative width will stretch the column to use the
/// remaining space.
void ResizeColumnsForTableView(QTableView* view, const std::initializer_list<int>& widths);
void ResizeColumnsForTreeView(QTreeView* view, const std::initializer_list<int>& widths);
/// Returns a string identifier for a Qt key ID.
QString GetKeyIdentifier(int key);
/// Returns the integer Qt key ID for an identifier.
std::optional<int> GetKeyIdForIdentifier(const QString& key_identifier);
/// Stringizes a key event.
QString KeyEventToString(int key, Qt::KeyboardModifiers mods);
/// Returns an integer id for a stringized key event. Modifiers are in the upper bits.
std::optional<int> ParseKeyString(const QString& key_str);
/// Returns a key id for a key event, including any modifiers.
int KeyEventToInt(int key, Qt::KeyboardModifiers mods);
/// Opens a URL with the default handler.
void OpenURL(QWidget* parent, const QUrl& qurl);
/// Opens a URL string with the default handler.
void OpenURL(QWidget* parent, const char* url);
/// Opens a URL string with the default handler.
void OpenURL(QWidget* parent, const QString& url);
// TODO: Get rid of wx interoperability later on.
wxString QStringToWxString(const QString& str);
QString WxStringToQString(const wxString& str);
} // namespace QtUtils

View File

@ -0,0 +1,417 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtCore/QtCore>
#include <optional>
#include <type_traits>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QtGui/QAction>
#else
#include <QtWidgets/QAction>
#endif
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QDoubleSpinBox>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QSlider>
#include <QtWidgets/QSpinBox>
#include "EmuThread.h"
#include "QtHost.h"
namespace SettingWidgetBinder
{
template <typename T>
struct SettingAccessor
{
static bool getBoolValue(const T* widget);
static void setBoolValue(T* widget, bool value);
static int getIntValue(const T* widget);
static void setIntValue(T* widget, int value);
static int getFloatValue(const T* widget);
static void setFloatValue(T* widget, int value);
static QString getStringValue(const T* widget);
static void setStringValue(T* widget, const QString& value);
template <typename F>
static void connectValueChanged(T* widget, F func);
};
template <>
struct SettingAccessor<QLineEdit>
{
static bool getBoolValue(const QLineEdit* widget) { return widget->text().toInt() != 0; }
static void setBoolValue(QLineEdit* widget, bool value)
{
widget->setText(value ? QStringLiteral("1") : QStringLiteral("0"));
}
static int getIntValue(const QLineEdit* widget) { return widget->text().toInt(); }
static void setIntValue(QLineEdit* widget, int value) { widget->setText(QString::number(value)); }
static float getFloatValue(const QLineEdit* widget) { return widget->text().toFloat(); }
static void setFloatValue(QLineEdit* widget, float value) { widget->setText(QString::number(value)); }
static QString getStringValue(const QLineEdit* widget) { return widget->text(); }
static void setStringValue(QLineEdit* widget, const QString& value) { widget->setText(value); }
template <typename F>
static void connectValueChanged(QLineEdit* widget, F func)
{
widget->connect(widget, &QLineEdit::textChanged, func);
}
};
template <>
struct SettingAccessor<QComboBox>
{
static bool getBoolValue(const QComboBox* widget) { return widget->currentIndex() > 0; }
static void setBoolValue(QComboBox* widget, bool value) { widget->setCurrentIndex(value ? 1 : 0); }
static int getIntValue(const QComboBox* widget) { return widget->currentIndex(); }
static void setIntValue(QComboBox* widget, int value) { widget->setCurrentIndex(value); }
static float getFloatValue(const QComboBox* widget) { return static_cast<float>(widget->currentIndex()); }
static void setFloatValue(QComboBox* widget, float value) { widget->setCurrentIndex(static_cast<int>(value)); }
static QString getStringValue(const QComboBox* widget)
{
const QVariant currentData(widget->currentData());
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (currentData.type() == QVariant::String)
return currentData.toString();
#else
if (currentData.metaType().id() == QMetaType::QString)
return currentData.toString();
#endif
return widget->currentText();
}
static void setStringValue(QComboBox* widget, const QString& value)
{
const int index = widget->findData(value);
if (index >= 0)
{
widget->setCurrentIndex(index);
return;
}
widget->setCurrentText(value);
}
template <typename F>
static void connectValueChanged(QComboBox* widget, F func)
{
widget->connect(widget, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), func);
}
};
template <>
struct SettingAccessor<QCheckBox>
{
static bool getBoolValue(const QCheckBox* widget) { return widget->isChecked(); }
static void setBoolValue(QCheckBox* widget, bool value) { widget->setChecked(value); }
static int getIntValue(const QCheckBox* widget) { return widget->isChecked() ? 1 : 0; }
static void setIntValue(QCheckBox* widget, int value) { widget->setChecked(value != 0); }
static float getFloatValue(const QCheckBox* widget) { return widget->isChecked() ? 1.0f : 0.0f; }
static void setFloatValue(QCheckBox* widget, float value) { widget->setChecked(value != 0.0f); }
static QString getStringValue(const QCheckBox* widget)
{
return widget->isChecked() ? QStringLiteral("1") : QStringLiteral("0");
}
static void setStringValue(QCheckBox* widget, const QString& value) { widget->setChecked(value.toInt() != 0); }
template <typename F>
static void connectValueChanged(QCheckBox* widget, F func)
{
widget->connect(widget, &QCheckBox::stateChanged, func);
}
};
template <>
struct SettingAccessor<QSlider>
{
static bool getBoolValue(const QSlider* widget) { return widget->value() > 0; }
static void setBoolValue(QSlider* widget, bool value) { widget->setValue(value ? 1 : 0); }
static int getIntValue(const QSlider* widget) { return widget->value(); }
static void setIntValue(QSlider* widget, int value) { widget->setValue(value); }
static float getFloatValue(const QSlider* widget) { return static_cast<float>(widget->value()); }
static void setFloatValue(QSlider* widget, float value) { widget->setValue(static_cast<int>(value)); }
static QString getStringValue(const QSlider* widget) { return QString::number(widget->value()); }
static void setStringValue(QSlider* widget, const QString& value) { widget->setValue(value.toInt()); }
template <typename F>
static void connectValueChanged(QSlider* widget, F func)
{
widget->connect(widget, &QSlider::valueChanged, func);
}
};
template <>
struct SettingAccessor<QSpinBox>
{
static bool getBoolValue(const QSpinBox* widget) { return widget->value() > 0; }
static void setBoolValue(QSpinBox* widget, bool value) { widget->setValue(value ? 1 : 0); }
static int getIntValue(const QSpinBox* widget) { return widget->value(); }
static void setIntValue(QSpinBox* widget, int value) { widget->setValue(value); }
static float getFloatValue(const QSpinBox* widget) { return static_cast<float>(widget->value()); }
static void setFloatValue(QSpinBox* widget, float value) { widget->setValue(static_cast<int>(value)); }
static QString getStringValue(const QSpinBox* widget) { return QString::number(widget->value()); }
static void setStringValue(QSpinBox* widget, const QString& value) { widget->setValue(value.toInt()); }
template <typename F>
static void connectValueChanged(QSpinBox* widget, F func)
{
widget->connect(widget, QOverload<int>::of(&QSpinBox::valueChanged), func);
}
};
template <>
struct SettingAccessor<QDoubleSpinBox>
{
static bool getBoolValue(const QDoubleSpinBox* widget) { return widget->value() > 0.0; }
static void setBoolValue(QDoubleSpinBox* widget, bool value) { widget->setValue(value ? 1.0 : 0.0); }
static int getIntValue(const QDoubleSpinBox* widget) { return static_cast<int>(widget->value()); }
static void setIntValue(QDoubleSpinBox* widget, int value) { widget->setValue(static_cast<double>(value)); }
static float getFloatValue(const QDoubleSpinBox* widget) { return static_cast<float>(widget->value()); }
static void setFloatValue(QDoubleSpinBox* widget, float value) { widget->setValue(static_cast<double>(value)); }
static QString getStringValue(const QDoubleSpinBox* widget) { return QString::number(widget->value()); }
static void setStringValue(QDoubleSpinBox* widget, const QString& value) { widget->setValue(value.toDouble()); }
template <typename F>
static void connectValueChanged(QDoubleSpinBox* widget, F func)
{
widget->connect(widget, QOverload<double>::of(&QDoubleSpinBox::valueChanged), func);
}
};
template <>
struct SettingAccessor<QAction>
{
static bool getBoolValue(const QAction* widget) { return widget->isChecked(); }
static void setBoolValue(QAction* widget, bool value) { widget->setChecked(value); }
static int getIntValue(const QAction* widget) { return widget->isChecked() ? 1 : 0; }
static void setIntValue(QAction* widget, int value) { widget->setChecked(value != 0); }
static float getFloatValue(const QAction* widget) { return widget->isChecked() ? 1.0f : 0.0f; }
static void setFloatValue(QAction* widget, float value) { widget->setChecked(value != 0.0f); }
static QString getStringValue(const QAction* widget)
{
return widget->isChecked() ? QStringLiteral("1") : QStringLiteral("0");
}
static void setStringValue(QAction* widget, const QString& value) { widget->setChecked(value.toInt() != 0); }
template <typename F>
static void connectValueChanged(QAction* widget, F func)
{
widget->connect(widget, &QAction::toggled, func);
}
};
/// Binds a widget's value to a setting, updating it when the value changes.
template <typename WidgetType>
static void BindWidgetToBoolSetting(WidgetType* widget, std::string section, std::string key, bool default_value)
{
using Accessor = SettingAccessor<WidgetType>;
bool value = QtHost::GetBaseBoolSettingValue(section.c_str(), key.c_str(), default_value);
Accessor::setBoolValue(widget, value);
Accessor::connectValueChanged(widget, [widget, section, key]() {
const bool new_value = Accessor::getBoolValue(widget);
QtHost::SetBaseBoolSettingValue(section.c_str(), key.c_str(), new_value);
g_emu_thread->applySettings();
});
}
template <typename WidgetType>
static void BindWidgetToIntSetting(WidgetType* widget, std::string section, std::string key, int default_value, int option_offset = 0)
{
using Accessor = SettingAccessor<WidgetType>;
s32 value = QtHost::GetBaseIntSettingValue(section.c_str(), key.c_str(), static_cast<s32>(default_value)) - option_offset;
Accessor::setIntValue(widget, static_cast<int>(value));
Accessor::connectValueChanged(widget, [widget, section, key, option_offset]() {
const int new_value = Accessor::getIntValue(widget);
QtHost::SetBaseIntSettingValue(section.c_str(), key.c_str(), new_value + option_offset);
g_emu_thread->applySettings();
});
}
template <typename WidgetType>
static void BindWidgetToFloatSetting(WidgetType* widget, std::string section, std::string key, float default_value)
{
using Accessor = SettingAccessor<WidgetType>;
float value = QtHost::GetBaseFloatSettingValue(section.c_str(), key.c_str(), default_value);
Accessor::setFloatValue(widget, value);
Accessor::connectValueChanged(widget, [widget, section, key]() {
const float new_value = Accessor::getFloatValue(widget);
QtHost::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
g_emu_thread->applySettings();
});
}
template <typename WidgetType>
static void BindWidgetToNormalizedSetting(WidgetType* widget, std::string section, std::string key, float range,
float default_value)
{
using Accessor = SettingAccessor<WidgetType>;
float value = QtHost::GetBaseFloatSettingValue(section.c_str(), key.c_str(), default_value);
Accessor::setIntValue(widget, static_cast<int>(value * range));
Accessor::connectValueChanged(widget, [widget, section, key, range]() {
const float new_value = (static_cast<float>(Accessor::getIntValue(widget)) / range);
QtHost::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
g_emu_thread->applySettings();
});
}
template <typename WidgetType>
static void BindWidgetToStringSetting(WidgetType* widget, std::string section, std::string key,
std::string default_value = std::string())
{
using Accessor = SettingAccessor<WidgetType>;
std::string value = QtHost::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str());
Accessor::setStringValue(widget, QString::fromStdString(value));
Accessor::connectValueChanged(widget, [widget, section, key]() {
const QString new_value = Accessor::getStringValue(widget);
if (!new_value.isEmpty())
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), new_value.toUtf8().constData());
else
QtHost::RemoveBaseSettingValue(section.c_str(), key.c_str());
g_emu_thread->applySettings();
});
}
template <typename WidgetType, typename DataType>
static void BindWidgetToEnumSetting(WidgetType* widget, std::string section, std::string key,
std::optional<DataType> (*from_string_function)(const char* str),
const char* (*to_string_function)(DataType value), DataType default_value)
{
using Accessor = SettingAccessor<WidgetType>;
using UnderlyingType = std::underlying_type_t<DataType>;
// TODO: Clean this up?
const std::string old_setting_string_value =
QtHost::GetBaseStringSettingValue(section.c_str(), key.c_str(), to_string_function(default_value));
const std::optional<DataType> old_setting_value = from_string_function(old_setting_string_value.c_str());
if (old_setting_value.has_value())
Accessor::setIntValue(widget, static_cast<int>(static_cast<UnderlyingType>(old_setting_value.value())));
else
Accessor::setIntValue(widget, static_cast<int>(static_cast<UnderlyingType>(default_value)));
Accessor::connectValueChanged(widget, [widget, section, key, to_string_function]() {
const DataType value = static_cast<DataType>(static_cast<UnderlyingType>(Accessor::getIntValue(widget)));
const char* string_value = to_string_function(value);
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), string_value);
g_emu_thread->applySettings();
});
}
template <typename WidgetType, typename DataType>
static void BindWidgetToEnumSetting(WidgetType* widget, std::string section, std::string key, const char** enum_names,
DataType default_value)
{
using Accessor = SettingAccessor<WidgetType>;
using UnderlyingType = std::underlying_type_t<DataType>;
const std::string old_setting_string_value = QtHost::GetBaseStringSettingValue(
section.c_str(), key.c_str(), enum_names[static_cast<UnderlyingType>(default_value)]);
UnderlyingType enum_index = static_cast<UnderlyingType>(default_value);
for (UnderlyingType i = 0; enum_names[i] != nullptr; i++)
{
if (old_setting_string_value == enum_names[i])
{
enum_index = i;
break;
}
}
Accessor::setIntValue(widget, static_cast<int>(enum_index));
Accessor::connectValueChanged(widget, [widget, section, key, enum_names]() {
const UnderlyingType value = static_cast<UnderlyingType>(Accessor::getIntValue(widget));
const char* string_value = enum_names[value];
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), string_value);
g_emu_thread->applySettings();
});
}
template <typename WidgetType>
static void BindWidgetToEnumSetting(WidgetType* widget, std::string section, std::string key, const char** enum_names,
const char** enum_values, const char* default_value)
{
using Accessor = SettingAccessor<WidgetType>;
const std::string old_setting_string_value =
QtHost::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value);
for (int i = 0; enum_names[i] != nullptr; i++)
widget->addItem(QString::fromUtf8(enum_names[i]));
int enum_index = -1;
for (int i = 0; enum_values[i] != nullptr; i++)
{
if (old_setting_string_value == enum_values[i])
{
enum_index = i;
break;
}
}
if (enum_index >= 0)
Accessor::setIntValue(widget, enum_index);
Accessor::connectValueChanged(widget, [widget, section, key, enum_values]() {
const int value = Accessor::getIntValue(widget);
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), enum_values[value]);
g_emu_thread->applySettings();
});
}
} // namespace SettingWidgetBinder

View File

@ -0,0 +1,50 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include <QtWidgets/QMessageBox>
#include <algorithm>
#include "AdvancedSystemSettingsWidget.h"
#include "EmuThread.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#include "SettingsDialog.h"
AdvancedSystemSettingsWidget::AdvancedSystemSettingsWidget(QWidget* parent, SettingsDialog* dialog)
: QWidget(parent)
{
m_ui.setupUi(this);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.eeRecompiler, "EmuCore/CPU/Recompiler", "EnableEE", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.eeCache, "EmuCore/CPU/Recompiler", "EnableEECache", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.eeINTCSpinDetection, "EmuCore/Speedhacks", "IntcStat", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.eeWaitLoopDetection, "EmuCore/Speedhacks", "WaitLoop", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.vu0Recompiler, "EmuCore/CPU/Recompiler", "EnableVU0", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.vu1Recompiler, "EmuCore/CPU/Recompiler", "EnableVU1", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.vuFlagHack, "EmuCore/Speedhacks", "vuFlagHack", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.iopRecompiler, "EmuCore/CPU/Recompiler", "EnableIOP", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.gameFixes, "", "EnableGameFixes", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.patches, "EmuCore", "EnablePatches", true);
SettingWidgetBinder::BindWidgetToFloatSetting(m_ui.ntscFrameRate, "EmuCore/GS", "FramerateNTSC", 59.94f);
SettingWidgetBinder::BindWidgetToFloatSetting(m_ui.palFrameRate, "EmuCore/GS", "FrameratePAL", 50.00f);
}
AdvancedSystemSettingsWidget::~AdvancedSystemSettingsWidget() = default;

View File

@ -0,0 +1,34 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtWidgets/QWidget>
#include "ui_AdvancedSystemSettingsWidget.h"
class SettingsDialog;
class AdvancedSystemSettingsWidget : public QWidget
{
Q_OBJECT
public:
AdvancedSystemSettingsWidget(QWidget* parent, SettingsDialog* dialog);
~AdvancedSystemSettingsWidget();
private:
Ui::AdvancedSystemSettingsWidget m_ui;
};

View File

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AdvancedSystemSettingsWidget</class>
<widget class="QWidget" name="AdvancedSystemSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>648</width>
<height>481</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>EmotionEngine (MIPS-IV)</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="eeRecompiler">
<property name="text">
<string>Enable Recompiler</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="eeWaitLoopDetection">
<property name="text">
<string>Wait Loop Detection</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="eeCache">
<property name="text">
<string>Enable Cache (Slow)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="eeINTCSpinDetection">
<property name="text">
<string>INTC Spin Detection</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Vector Units (VU)</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="2" column="0">
<widget class="QCheckBox" name="vuFlagHack">
<property name="text">
<string>mVU Flag Hack</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="vu0Recompiler">
<property name="text">
<string>Enable VU0 Recompiler (Micro Mode)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="vu1Recompiler">
<property name="text">
<string>Enable VU1 Recompiler</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>I/O Processor (IOP, MIPS-I)</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="iopRecompiler">
<property name="text">
<string>Enable Recompiler</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Game Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="gameFixes">
<property name="text">
<string>Enable Game Fixes</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="patches">
<property name="text">
<string>Enable Compatibility Patches</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="basicGroupBox">
<property name="title">
<string>Frame Rate Control</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="palFrameRate">
<property name="suffix">
<string> hz</string>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="ntscFrameRate">
<property name="suffix">
<string> hz</string>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>PAL Frame Rate:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>NTSC Frame Rate:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,179 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include <QtGui/QIcon>
#include <QtWidgets/QFileDialog>
#include <algorithm>
#include "pcsx2/ps2/BiosTools.h"
#include "BIOSSettingsWidget.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#include "SettingsDialog.h"
BIOSSettingsWidget::BIOSSettingsWidget(QWidget* parent, SettingsDialog* dialog)
: QWidget(parent)
{
m_ui.setupUi(this);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.fastBoot, "EmuCore", "EnableFastBoot", true);
dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Unchecked"),
tr("Patches the BIOS to skip the console's boot animation."));
updateSearchDirectory();
refreshList();
connect(m_ui.searchDirectory, &QLineEdit::textChanged, [this](const QString& text) {
QtHost::SetBaseStringSettingValue("Folders", "Bios", text.toUtf8().constData());
QtHost::UpdateFolders();
refreshList();
});
connect(m_ui.resetSearchDirectory, &QPushButton::clicked, [this]() {
QtHost::RemoveBaseSettingValue("Folders", "Bios");
QtHost::UpdateFolders();
updateSearchDirectory();
refreshList();
});
connect(m_ui.browseSearchDirectory, &QPushButton::clicked, this, &BIOSSettingsWidget::browseSearchDirectory);
connect(m_ui.openSearchDirectory, &QPushButton::clicked, this, &BIOSSettingsWidget::openSearchDirectory);
connect(m_ui.refresh, &QPushButton::clicked, this, &BIOSSettingsWidget::refreshList);
connect(m_ui.fileList, &QTreeWidget::currentItemChanged, this, &BIOSSettingsWidget::listItemChanged);
}
BIOSSettingsWidget::~BIOSSettingsWidget()
{
if (m_refresh_thread)
m_refresh_thread->wait();
}
void BIOSSettingsWidget::refreshList()
{
if (m_refresh_thread)
{
m_refresh_thread->wait();
delete m_refresh_thread;
}
QSignalBlocker blocker(m_ui.fileList);
m_ui.fileList->clear();
m_ui.fileList->setEnabled(false);
m_refresh_thread = new RefreshThread(this, m_ui.searchDirectory->text());
m_refresh_thread->start();
}
void BIOSSettingsWidget::browseSearchDirectory()
{
QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(
QtUtils::GetRootWidget(this), tr("Select Directory"), m_ui.searchDirectory->text()));
if (directory.isEmpty())
return;
m_ui.searchDirectory->setText(directory);
}
void BIOSSettingsWidget::openSearchDirectory()
{
QtUtils::OpenURL(this, QUrl::fromLocalFile(m_ui.searchDirectory->text()));
}
void BIOSSettingsWidget::updateSearchDirectory()
{
// this will generate a full path
m_ui.searchDirectory->setText(QtUtils::WxStringToQString(EmuFolders::Bios.ToString()));
}
void BIOSSettingsWidget::listRefreshed(const QVector<BIOSInfo>& items)
{
const std::string selected_bios(QtHost::GetBaseStringSettingValue("Filenames", "BIOS"));
QSignalBlocker sb(m_ui.fileList);
for (const BIOSInfo& bi : items)
{
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, QString::fromStdString(bi.filename));
item->setText(1, QString::fromStdString(bi.description));
switch (bi.region)
{
case 2: // Japan
item->setIcon(0, QIcon(QStringLiteral(":/icons/flag-jp.png")));
break;
case 3: // USA
item->setIcon(0, QIcon(QStringLiteral(":/icons/flag-us.png")));
break;
case 4: // Europe
item->setIcon(0, QIcon(QStringLiteral(":/icons/flag-eu.png")));
break;
case 5: // HK
case 6: // Free
case 7: // China
case 0: // T10K
case 1: // Test
default:
item->setIcon(0, QIcon(QStringLiteral(":/icons/flag-jp.png")));
break;
}
m_ui.fileList->addTopLevelItem(item);
if (bi.filename == selected_bios)
item->setSelected(true);
}
m_ui.fileList->setEnabled(true);
}
void BIOSSettingsWidget::listItemChanged(const QTreeWidgetItem* current, const QTreeWidgetItem* previous)
{
QtHost::SetBaseStringSettingValue("Filenames", "BIOS", current->text(0).toUtf8().constData());
}
BIOSSettingsWidget::RefreshThread::RefreshThread(BIOSSettingsWidget* parent, const QString& directory)
: QThread(parent)
, m_parent(parent)
, m_directory(directory)
{
}
BIOSSettingsWidget::RefreshThread::~RefreshThread() = default;
void BIOSSettingsWidget::RefreshThread::run()
{
QVector<BIOSInfo> items;
QDir dir(m_directory);
if (dir.exists())
{
for (const QFileInfo& info : dir.entryInfoList(QDir::Files))
{
BIOSInfo bi;
QString full_path(info.absoluteFilePath());
if (!IsBIOS(full_path.toUtf8().constData(), bi.version, bi.description, bi.region, bi.zone))
continue;
bi.filename = info.fileName().toStdString();
items.push_back(std::move(bi));
}
}
QMetaObject::invokeMethod(m_parent, "listRefreshed", Qt::QueuedConnection, Q_ARG(const QVector<BIOSInfo>&, items));
}

View File

@ -0,0 +1,75 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtCore/QDir>
#include <QtCore/QString>
#include <QtCore/QPair>
#include <QtCore/QVector>
#include <QtWidgets/QWidget>
#include <string>
#include "ui_BIOSSettingsWidget.h"
class SettingsDialog;
class QThread;
// TODO: Move to core.
struct BIOSInfo
{
std::string filename;
std::string description;
std::string zone;
u32 version;
u32 region;
};
Q_DECLARE_METATYPE(BIOSInfo);
class BIOSSettingsWidget : public QWidget
{
Q_OBJECT
public:
BIOSSettingsWidget(QWidget* parent, SettingsDialog* dialog);
~BIOSSettingsWidget();
private Q_SLOTS:
void refreshList();
void browseSearchDirectory();
void openSearchDirectory();
void updateSearchDirectory();
void listItemChanged(const QTreeWidgetItem* current, const QTreeWidgetItem* previous);
void listRefreshed(const QVector<BIOSInfo>& items);
private:
Ui::BIOSSettingsWidget m_ui;
class RefreshThread final : public QThread
{
public:
RefreshThread(BIOSSettingsWidget* parent, const QString& directory);
~RefreshThread();
protected:
void run() override;
private:
BIOSSettingsWidget* m_parent;
QString m_directory;
};
RefreshThread* m_refresh_thread = nullptr;
};

View File

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BIOSSettingsWidget</class>
<widget class="QWidget" name="BIOSSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>618</width>
<height>408</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_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>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>BIOS Directory</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>PCSX2 will search for BIOS images in this directory.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="searchDirectory"/>
</item>
<item>
<widget class="QPushButton" name="browseSearchDirectory">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="resetSearchDirectory">
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>BIOS Selection</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="openSearchDirectory">
<property name="text">
<string>Open in Explorer...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="refresh">
<property name="text">
<string>Refresh List</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QTreeWidget" name="fileList">
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<column>
<property name="text">
<string>Filename</string>
</property>
</column>
<column>
<property name="text">
<string>Version</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Options and Patches</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="fastBoot">
<property name="text">
<string>Fast Boot</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ControllerBindingWidget</class>
<widget class="QWidget" name="ControllerBindingWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>834</width>
<height>560</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0">
<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>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Controller Type</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="controllerType"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>460</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="automaticBinding">
<property name="text">
<string>Automatic binding</string>
</property>
<property name="icon">
<iconset theme="gamepad-line">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="loadProfile">
<property name="text">
<string>Load Profile</string>
</property>
<property name="icon">
<iconset theme="folder-open-line">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="saveProfile">
<property name="text">
<string>Save Profile</string>
</property>
<property name="icon">
<iconset theme="save-3-line">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,158 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include <QtWidgets/QMessageBox>
#include <algorithm>
#include "ControllerBindingWidgets.h"
#include "ControllerSettingsDialog.h"
#include "EmuThread.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#include "SettingsDialog.h"
#include "common/StringUtil.h"
#include "pcsx2/PAD/Host/PAD.h"
ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port)
: QWidget(parent)
, m_dialog(dialog)
, m_config_section(StringUtil::StdStringFromFormat("Pad%u", port + 1u))
, m_port_number(port)
{
m_ui.setupUi(this);
populateControllerTypes();
onTypeChanged();
SettingWidgetBinder::BindWidgetToStringSetting(m_ui.controllerType, m_config_section, "Type", "None");
connect(m_ui.controllerType, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ControllerBindingWidget::onTypeChanged);
}
ControllerBindingWidget::~ControllerBindingWidget()
{
}
void ControllerBindingWidget::populateControllerTypes()
{
m_ui.controllerType->addItem(tr("None (Not Connected)"), QStringLiteral("None"));
for (const std::string& type : PAD::GetControllerTypeNames())
m_ui.controllerType->addItem(QString::fromStdString(type), QString::fromStdString(type));
}
void ControllerBindingWidget::onTypeChanged()
{
if (m_current_widget)
{
m_ui.verticalLayout->removeWidget(m_current_widget);
delete m_current_widget;
m_current_widget = nullptr;
}
m_controller_type = QtHost::GetBaseStringSettingValue(m_config_section.c_str(), "Type");
const int index = m_ui.controllerType->findData(QString::fromStdString(m_controller_type));
if (index >= 0 && index != m_ui.controllerType->currentIndex())
{
QSignalBlocker sb(m_ui.controllerType);
m_ui.controllerType->setCurrentIndex(index);
}
if (m_controller_type == "DualShock2")
m_current_widget = ControllerBindingWidget_DualShock2::createInstance(this);
else
m_current_widget = new ControllerBindingWidget_Base(this);
m_ui.verticalLayout->addWidget(m_current_widget, 1);
}
//////////////////////////////////////////////////////////////////////////
ControllerBindingWidget_Base::ControllerBindingWidget_Base(ControllerBindingWidget* parent)
: QWidget(parent)
{
}
ControllerBindingWidget_Base::~ControllerBindingWidget_Base()
{
}
void ControllerBindingWidget_Base::initBindingWidgets()
{
const std::string& type = getControllerType();
const std::string& config_section = getConfigSection();
std::vector<std::string> bindings(PAD::GetControllerBinds(type));
for (std::string& binding : bindings)
{
InputBindingWidget* widget = findChild<InputBindingWidget*>(QString::fromStdString(binding));
if (!widget)
{
Console.Error("(ControllerBindingWidget_Base) No widget found for '%s' (%*s)",
binding.c_str(), static_cast<int>(type.size()), type.data());
continue;
}
widget->setKey(config_section, std::move(binding));
}
const PAD::VibrationCapabilities vibe_caps = PAD::GetControllerVibrationCapabilities(type);
switch (vibe_caps)
{
case PAD::VibrationCapabilities::LargeSmallMotors:
{
InputVibrationBindingWidget* widget = findChild<InputVibrationBindingWidget*>(QStringLiteral("LargeMotor"));
if (widget)
widget->setKey(getDialog(), config_section, "LargeMotor");
widget = findChild<InputVibrationBindingWidget*>(QStringLiteral("SmallMotor"));
if (widget)
widget->setKey(getDialog(), config_section, "SmallMotor");
}
break;
case PAD::VibrationCapabilities::SingleMotor:
{
InputVibrationBindingWidget* widget = findChild<InputVibrationBindingWidget*>(QStringLiteral("Motor"));
if (widget)
widget->setKey(getDialog(), config_section, "Motor");
}
break;
case PAD::VibrationCapabilities::NoVibration:
default:
break;
}
}
ControllerBindingWidget_DualShock2::ControllerBindingWidget_DualShock2(ControllerBindingWidget* parent)
: ControllerBindingWidget_Base(parent)
{
m_ui.setupUi(this);
initBindingWidgets();
}
ControllerBindingWidget_DualShock2::~ControllerBindingWidget_DualShock2()
{
}
ControllerBindingWidget_Base* ControllerBindingWidget_DualShock2::createInstance(ControllerBindingWidget* parent)
{
return new ControllerBindingWidget_DualShock2(parent);
}
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,86 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtWidgets/QWidget>
#include "ui_ControllerBindingWidget.h"
#include "ui_ControllerBindingWidget_DualShock2.h"
class InputBindingWidget;
class ControllerSettingsDialog;
class ControllerBindingWidget_Base;
class ControllerBindingWidget final : public QWidget
{
Q_OBJECT
public:
ControllerBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port);
~ControllerBindingWidget();
__fi ControllerSettingsDialog* getDialog() const { return m_dialog; }
__fi const std::string& getConfigSection() const { return m_config_section; }
__fi const std::string& getControllerType() const { return m_controller_type; }
__fi u32 getPortNumber() const { return m_port_number; }
private Q_SLOTS:
void onTypeChanged();
private:
void populateControllerTypes();
Ui::ControllerBindingWidget m_ui;
ControllerSettingsDialog* m_dialog;
std::string m_config_section;
std::string m_controller_type;
u32 m_port_number;
ControllerBindingWidget_Base* m_current_widget = nullptr;
};
class ControllerBindingWidget_Base : public QWidget
{
Q_OBJECT
public:
ControllerBindingWidget_Base(ControllerBindingWidget* parent);
virtual ~ControllerBindingWidget_Base();
__fi ControllerSettingsDialog* getDialog() const { return static_cast<ControllerBindingWidget*>(parent())->getDialog(); }
__fi const std::string& getConfigSection() const { return static_cast<ControllerBindingWidget*>(parent())->getConfigSection(); }
__fi const std::string& getControllerType() const { return static_cast<ControllerBindingWidget*>(parent())->getControllerType(); }
__fi u32 getPortNumber() const { return static_cast<ControllerBindingWidget*>(parent())->getPortNumber(); }
protected:
void initBindingWidgets();
};
class ControllerBindingWidget_DualShock2 final : public ControllerBindingWidget_Base
{
Q_OBJECT
public:
ControllerBindingWidget_DualShock2(ControllerBindingWidget* parent);
~ControllerBindingWidget_DualShock2();
static ControllerBindingWidget_Base* createInstance(ControllerBindingWidget* parent);
private:
Ui::ControllerBindingWidget_DualShock2 m_ui;
};

View File

@ -0,0 +1,64 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Frontend/InputManager.h"
#include "Settings/ControllerGlobalSettingsWidget.h"
#include "Settings/ControllerSettingsDialog.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent, ControllerSettingsDialog* dialog)
: QWidget(parent)
{
m_ui.setupUi(this);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.enableSDLSource, "InputSources", "SDL", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.enableXInputSource, "InputSources", "XInput", false);
connect(m_ui.enableSDLSource, &QCheckBox::stateChanged, this, &ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
updateSDLOptionsEnabled();
}
ControllerGlobalSettingsWidget::~ControllerGlobalSettingsWidget() = default;
void ControllerGlobalSettingsWidget::addDeviceToList(const QString& identifier, const QString& name)
{
QListWidgetItem* item = new QListWidgetItem();
item->setText(QStringLiteral("%1: %2").arg(identifier).arg(name));
item->setData(Qt::UserRole, identifier);
m_ui.deviceList->addItem(item);
}
void ControllerGlobalSettingsWidget::removeDeviceFromList(const QString& identifier)
{
const int count = m_ui.deviceList->count();
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = m_ui.deviceList->item(i);
if (item->data(Qt::UserRole) != identifier)
continue;
delete m_ui.deviceList->takeItem(i);
}
}
void ControllerGlobalSettingsWidget::updateSDLOptionsEnabled()
{
const bool enabled = m_ui.enableSDLSource->isChecked();
m_ui.enableSDLEnhancedMode->setEnabled(enabled);
}

View File

@ -0,0 +1,42 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtWidgets/QWidget>
#include <QtCore/QMap>
#include <array>
#include <vector>
#include "ui_ControllerGlobalSettingsWidget.h"
class ControllerSettingsDialog;
class ControllerGlobalSettingsWidget : public QWidget
{
Q_OBJECT
public:
ControllerGlobalSettingsWidget(QWidget* parent, ControllerSettingsDialog* dialog);
~ControllerGlobalSettingsWidget();
void addDeviceToList(const QString& identifier, const QString& name);
void removeDeviceFromList(const QString& identifier);
private:
void updateSDLOptionsEnabled();
Ui::ControllerGlobalSettingsWidget m_ui;
};

View File

@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ControllerGlobalSettingsWidget</class>
<widget class="QWidget" name="ControllerGlobalSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>880</width>
<height>712</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
<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>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>SDL Input Source</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>The SDL input source supports most controllers, and provides advanced functionality for Dualshock 4/Dualsense pads in Bluetooth mode (Vibration/LED Control).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="enableSDLSource">
<property name="text">
<string>Enable SDL Input Source</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="enableSDLEnhancedMode">
<property name="text">
<string>Dualshock 4/Dualsense Enhanced Mode</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>XInput Source</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>The XInput source provides support for XBox 360/XBox One/XBox Series controllers, and third party controllers which implement the XInput protocol.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="enableXInputSource">
<property name="text">
<string>Enable XInput Input Source</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Controller Multitap</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>The multitap enables up to 8 controllers to be connected to the console. Each multitap provides 4 ports. Multitap is not supported by all games. (NOT YET IMPLEMENTED)</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="multitapPort1">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Multitap on Console Port 1</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="multitapPort2">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Multitap on Console Port 2</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Detected Devices</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QListWidget" name="deviceList">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,119 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "EmuThread.h"
#include "QtHost.h"
#include "Settings/ControllerSettingsDialog.h"
#include "Settings/ControllerGlobalSettingsWidget.h"
#include "Settings/ControllerBindingWidgets.h"
#include "Settings/HotkeySettingsWidget.h"
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QTextEdit>
ControllerSettingsDialog::ControllerSettingsDialog(QWidget* parent /* = nullptr */)
: QDialog(parent)
{
m_ui.setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_global_settings = new ControllerGlobalSettingsWidget(m_ui.settingsContainer, this);
m_ui.settingsContainer->insertWidget(0, m_global_settings);
for (u32 i = 0; i < MAX_PORTS; i++)
{
m_port_bindings[i] = new ControllerBindingWidget(m_ui.settingsContainer, this, i);
m_ui.settingsContainer->insertWidget(i + 1, m_port_bindings[i]);
}
m_hotkey_settings = new HotkeySettingsWidget(m_ui.settingsContainer, this);
m_ui.settingsContainer->insertWidget(3, m_hotkey_settings);
m_ui.settingsCategory->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, &ControllerSettingsDialog::onCategoryCurrentRowChanged);
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &ControllerSettingsDialog::close);
connect(g_emu_thread, &EmuThread::onInputDevicesEnumerated, this, &ControllerSettingsDialog::onInputDevicesEnumerated);
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &ControllerSettingsDialog::onInputDeviceConnected);
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this, &ControllerSettingsDialog::onInputDeviceDisconnected);
connect(g_emu_thread, &EmuThread::onVibrationMotorsEnumerated, this, &ControllerSettingsDialog::onVibrationMotorsEnumerated);
// trigger a device enumeration to populate the device list
g_emu_thread->enumerateInputDevices();
g_emu_thread->enumerateVibrationMotors();
}
ControllerSettingsDialog::~ControllerSettingsDialog() = default;
void ControllerSettingsDialog::setCategory(Category category)
{
switch (category)
{
case Category::GlobalSettings:
m_ui.settingsCategory->setCurrentRow(0);
break;
// TODO: These will need to take multitap into consideration in the future.
case Category::FirstControllerSettings:
m_ui.settingsCategory->setCurrentRow(1);
break;
case Category::HotkeySettings:
m_ui.settingsCategory->setCurrentRow(3);
break;
default:
break;
}
}
void ControllerSettingsDialog::onCategoryCurrentRowChanged(int row)
{
m_ui.settingsContainer->setCurrentIndex(row);
}
void ControllerSettingsDialog::onInputDevicesEnumerated(const QList<QPair<QString, QString>>& devices)
{
for (const QPair<QString, QString>& device : devices)
m_global_settings->addDeviceToList(device.first, device.second);
}
void ControllerSettingsDialog::onInputDeviceConnected(const QString& identifier, const QString& device_name)
{
m_global_settings->addDeviceToList(identifier, device_name);
g_emu_thread->enumerateVibrationMotors();
}
void ControllerSettingsDialog::onInputDeviceDisconnected(const QString& identifier)
{
m_global_settings->removeDeviceFromList(identifier);
g_emu_thread->enumerateVibrationMotors();
}
void ControllerSettingsDialog::onVibrationMotorsEnumerated(const QList<InputBindingKey>& motors)
{
m_vibration_motors.clear();
m_vibration_motors.reserve(motors.size());
for (const InputBindingKey key : motors)
{
const std::string key_str(InputManager::ConvertInputBindingKeyToString(key));
if (!key_str.empty())
m_vibration_motors.push_back(QString::fromStdString(key_str));
}
}

View File

@ -0,0 +1,74 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ui_ControllerSettingsDialog.h"
#include "Frontend/InputManager.h"
#include <QtCore/QList>
#include <QtCore/QPair>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtWidgets/QDialog>
#include <array>
class ControllerGlobalSettingsWidget;
class ControllerBindingWidget;
class HotkeySettingsWidget;
class ControllerSettingsDialog final : public QDialog
{
Q_OBJECT
public:
enum class Category
{
GlobalSettings,
FirstControllerSettings,
HotkeySettings,
Count
};
enum : u32
{
MAX_PORTS = 2
};
ControllerSettingsDialog(QWidget* parent = nullptr);
~ControllerSettingsDialog();
HotkeySettingsWidget* getHotkeySettingsWidget() const { return m_hotkey_settings; }
__fi const QStringList& getVibrationMotors() const { return m_vibration_motors; }
public Q_SLOTS:
void setCategory(Category category);
private Q_SLOTS:
void onCategoryCurrentRowChanged(int row);
void onInputDevicesEnumerated(const QList<QPair<QString, QString>>& devices);
void onInputDeviceConnected(const QString& identifier, const QString& device_name);
void onInputDeviceDisconnected(const QString& identifier);
void onVibrationMotorsEnumerated(const QList<InputBindingKey>& motors);
private:
Ui::ControllerSettingsDialog m_ui;
ControllerGlobalSettingsWidget* m_global_settings = nullptr;
std::array<ControllerBindingWidget*, MAX_PORTS> m_port_bindings{};
HotkeySettingsWidget* m_hotkey_settings = nullptr;
QStringList m_vibration_motors;
};

View File

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ControllerSettingsDialog</class>
<widget class="QDialog" name="ControllerSettingsDialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1274</width>
<height>668</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>PCSX2 Controller Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0">
<item row="0" column="0">
<widget class="QListWidget" name="settingsCategory">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<item>
<property name="text">
<string>Global Settings</string>
</property>
<property name="icon">
<iconset theme="settings-3-line">
<normaloff>.</normaloff>.</iconset>
</property>
</item>
<item>
<property name="text">
<string>Controller 1</string>
</property>
<property name="icon">
<iconset theme="gamepad-line">
<normaloff>.</normaloff>.</iconset>
</property>
</item>
<item>
<property name="text">
<string>Controller 2</string>
</property>
<property name="icon">
<iconset theme="gamepad-line">
<normaloff>.</normaloff>.</iconset>
</property>
</item>
<item>
<property name="text">
<string>Hotkeys</string>
</property>
<property name="icon">
<iconset theme="keyboard-line">
<normaloff>.</normaloff>.</iconset>
</property>
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QStackedWidget" name="settingsContainer">
<property name="minimumSize">
<size>
<width>1100</width>
<height>620</height>
</size>
</property>
<property name="currentIndex">
<number>4</number>
</property>
<widget class="QWidget" name="page"/>
<widget class="QWidget" name="page_3"/>
<widget class="QWidget" name="page_4"/>
<widget class="QWidget" name="page_5"/>
<widget class="QWidget" name="page_6"/>
<widget class="QWidget" name="page_2"/>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,165 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include <QtWidgets/QMessageBox>
#include <limits>
#include "EmulationSettingsWidget.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#include "SettingsDialog.h"
static constexpr u32 DEFAULT_FRAME_LATENCY = 2;
static void FillComboBoxWithEmulationSpeeds(QComboBox* cb)
{
cb->addItem(qApp->translate("GeneralSettingsWidget", "Unlimited"), QVariant(0.0f));
static const int speeds[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175,
200, 250, 300, 350, 400, 450, 500, 600, 700, 800, 900, 1000};
for (const int speed : speeds)
{
cb->addItem(qApp->translate("EmulationSettingsWidget", "%1% [%2 FPS (NTSC) / %3 FPS (PAL)]")
.arg(speed)
.arg((60 * speed) / 100)
.arg((50 * speed) / 100),
QVariant(static_cast<float>(speed) / 100.0f));
}
}
EmulationSettingsWidget::EmulationSettingsWidget(QWidget* parent, SettingsDialog* dialog)
: QWidget(parent)
{
m_ui.setupUi(this);
FillComboBoxWithEmulationSpeeds(m_ui.normalSpeed);
if (const int index =
m_ui.normalSpeed->findData(QVariant(QtHost::GetBaseFloatSettingValue("Framerate", "NominalScalar", 1.0f)));
index >= 0)
{
m_ui.normalSpeed->setCurrentIndex(index);
}
connect(m_ui.normalSpeed, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&EmulationSettingsWidget::onNormalSpeedIndexChanged);
FillComboBoxWithEmulationSpeeds(m_ui.fastForwardSpeed);
if (const int index =
m_ui.fastForwardSpeed->findData(QVariant(QtHost::GetBaseFloatSettingValue("Framerate", "TurboScalar", 2.0f)));
index >= 0)
{
m_ui.fastForwardSpeed->setCurrentIndex(index);
}
connect(m_ui.fastForwardSpeed, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&EmulationSettingsWidget::onFastForwardSpeedIndexChanged);
FillComboBoxWithEmulationSpeeds(m_ui.slowMotionSpeed);
if (const int index =
m_ui.slowMotionSpeed->findData(QVariant(QtHost::GetBaseFloatSettingValue("Framerate", "SlomoScalar", 0.5f)));
index >= 0)
{
m_ui.slowMotionSpeed->setCurrentIndex(index);
}
connect(m_ui.slowMotionSpeed, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&EmulationSettingsWidget::onSlowMotionSpeedIndexChanged);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.speedLimiter, "EmuCore/GS", "FrameLimitEnable", true);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.maxFrameLatency, "EmuCore/GS", "VsyncQueueSize", DEFAULT_FRAME_LATENCY);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.syncToHostRefreshRate, "EmuCore/GS", "SyncToHostRefreshRate",
false);
connect(m_ui.optimalFramePacing, &QCheckBox::toggled, this, &EmulationSettingsWidget::onOptimalFramePacingChanged);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.cheats, "EmuCore", "EnableCheats", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.widescreenPatches, "EmuCore", "EnableWideScreenPatches", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.perGameSettings, "EmuCore", "EnablePerGameSettings", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.hostFilesystem, "EmuCore", "HostFs", false);
dialog->registerWidgetHelp(
m_ui.normalSpeed, tr("Normal Speed"), "100%",
tr("Sets the target emulation speed. It is not guaranteed that this speed will be reached, "
"and if not, the emulator will run as fast as it can manage."));
dialog->registerWidgetHelp(
m_ui.fastForwardSpeed, tr("Fast Forward Speed"), tr("User Preference"),
tr("Sets the fast forward speed. This speed will be used when the fast forward hotkey is pressed/toggled."));
dialog->registerWidgetHelp(
m_ui.slowMotionSpeed, tr("Slow Motion Speed"), tr("User Preference"),
tr("Sets the slow motion speed. This speed will be used when the slow motion hotkey is pressed/toggled."));
dialog->registerWidgetHelp(
m_ui.syncToHostRefreshRate, tr("Sync To Host Refresh Rate"), tr("Unchecked"),
tr("Adjusts the emulation speed so the console's refresh rate matches the host's refresh rate when both VSync and "
"Audio Resampling settings are enabled. This results in the smoothest animations possible, at the cost of "
"potentially increasing the emulation speed by less than 1%. Sync To Host Refresh Rate will not take effect if "
"the console's refresh rate is too far from the host's refresh rate. Users with variable refresh rate displays "
"should disable this option."));
dialog->registerWidgetHelp(m_ui.cheats, tr("Enable Cheats"), tr("Unchecked"),
tr("Automatically loads and applies cheats on game start."));
dialog->registerWidgetHelp(
m_ui.perGameSettings, tr("Enable Per-Game Settings"), tr("Checked"),
tr("When enabled, per-game settings will be applied, and incompatible enhancements will be disabled. You should "
"leave this option enabled except when testing enhancements with incompatible games."));
updateOptimalFramePacing();
}
EmulationSettingsWidget::~EmulationSettingsWidget() = default;
void EmulationSettingsWidget::onNormalSpeedIndexChanged(int index)
{
bool okay;
const float value = m_ui.normalSpeed->currentData().toFloat(&okay);
QtHost::SetBaseFloatSettingValue("Framerate", "NominalScalar", okay ? value : 1.0f);
g_emu_thread->applySettings();
}
void EmulationSettingsWidget::onFastForwardSpeedIndexChanged(int index)
{
bool okay;
const float value = m_ui.fastForwardSpeed->currentData().toFloat(&okay);
QtHost::SetBaseFloatSettingValue("Framerate", "TurboScalar", okay ? value : 1.0f);
g_emu_thread->applySettings();
}
void EmulationSettingsWidget::onSlowMotionSpeedIndexChanged(int index)
{
bool okay;
const float value = m_ui.slowMotionSpeed->currentData().toFloat(&okay);
QtHost::SetBaseFloatSettingValue("Framerate", "SlomoScalar", okay ? value : 1.0f);
g_emu_thread->applySettings();
}
void EmulationSettingsWidget::onOptimalFramePacingChanged(bool checked)
{
const QSignalBlocker sb(m_ui.maxFrameLatency);
m_ui.maxFrameLatency->setValue(DEFAULT_FRAME_LATENCY);
m_ui.maxFrameLatency->setEnabled(!checked);
QtHost::SetBaseIntSettingValue("EmuCore/GS", "VsyncQueueSize", checked ? 0 : DEFAULT_FRAME_LATENCY);
g_emu_thread->applySettings();
}
void EmulationSettingsWidget::updateOptimalFramePacing()
{
const int value = QtHost::GetBaseIntSettingValue("EmuCore/GS", "VsyncQueueSize", DEFAULT_FRAME_LATENCY);
const bool optimal = (value == 0);
const QSignalBlocker sb(m_ui.optimalFramePacing);
m_ui.optimalFramePacing->setChecked(optimal);
const QSignalBlocker sb2(m_ui.maxFrameLatency);
m_ui.maxFrameLatency->setEnabled(!optimal);
m_ui.maxFrameLatency->setValue(optimal ? DEFAULT_FRAME_LATENCY : value);
}

View File

@ -0,0 +1,42 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtWidgets/QWidget>
#include "ui_EmulationSettingsWidget.h"
class SettingsDialog;
class EmulationSettingsWidget : public QWidget
{
Q_OBJECT
public:
EmulationSettingsWidget(QWidget* parent, SettingsDialog* dialog);
~EmulationSettingsWidget();
private Q_SLOTS:
void onNormalSpeedIndexChanged(int index);
void onFastForwardSpeedIndexChanged(int index);
void onSlowMotionSpeedIndexChanged(int index);
void onOptimalFramePacingChanged(bool checked);
private:
void updateOptimalFramePacing();
Ui::EmulationSettingsWidget m_ui;
};

View File

@ -0,0 +1,178 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EmulationSettingsWidget</class>
<widget class="QWidget" name="EmulationSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>672</width>
<height>518</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>Speed Control</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="1">
<widget class="QComboBox" name="fastForwardSpeed"/>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="slowMotionSpeed"/>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="normalSpeed"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Normal Speed:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Slow Motion Speed:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Fast Forward Speed:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="speedLimiter">
<property name="text">
<string>Enable Speed Limiter</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="basicGroupBox">
<property name="title">
<string>Frame Pacing/Latency Control</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="QSpinBox" name="maxFrameLatency">
<property name="suffix">
<string> frames</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>5</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Maximum Frame Latency:</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<layout class="QGridLayout" name="basicCheckboxGridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="optimalFramePacing">
<property name="text">
<string>Optimal Frame Pacing</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="syncToHostRefreshRate">
<property name="text">
<string>Adjust To Host Refresh Rate</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Game Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QCheckBox" name="perGameSettings">
<property name="text">
<string>Enable Per-Game Settings</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="cheats">
<property name="text">
<string>Enable Cheats</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="widescreenPatches">
<property name="text">
<string>Enable Widescreen Patches</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="hostFilesystem">
<property name="text">
<string>Enable Host Filesystem</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,50 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include <QtWidgets/QMessageBox>
#include <algorithm>
#include "GameFixSettingsWidget.h"
#include "EmuThread.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#include "SettingsDialog.h"
GameFixSettingsWidget::GameFixSettingsWidget(QWidget* parent, SettingsDialog* dialog)
: QWidget(parent)
{
m_ui.setupUi(this);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.FpuMulHack, "EmuCore/Gamefixes", "FpuMulHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.FpuNegDivHack, "EmuCore/Gamefixes", "FpuNegDivHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.GoemonTlbHack, "EmuCore/Gamefixes", "GoemonTlbHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.SoftwareRendererFMVHack, "EmuCore/Gamefixes", "SoftwareRendererFMVHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.SkipMPEGHack, "EmuCore/Gamefixes", "SkipMPEGHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.OPHFlagHack, "EmuCore/Gamefixes", "OPHFlagHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.EETimingHack, "EmuCore/Gamefixes", "EETimingHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.DMABusyHack, "EmuCore/Gamefixes", "DMABusyHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.GIFFIFOHack, "EmuCore/Gamefixes", "GIFFIFOHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.VIFFIFOHack, "EmuCore/Gamefixes", "VIFFIFOHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.VIF1StallHack, "EmuCore/Gamefixes", "VIF1StallHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.VuAddSubHack, "EmuCore/Gamefixes", "VuAddSubHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.IbitHack, "EmuCore/Gamefixes", "IbitHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.VUKickstartHack, "EmuCore/Gamefixes", "VUKickstartHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.VUOverflowHack, "EmuCore/Gamefixes", "VUOverflowHack", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.XgKickHack, "EmuCore/Gamefixes", "XgKickHack", false);
}
GameFixSettingsWidget::~GameFixSettingsWidget() = default;

View File

@ -0,0 +1,34 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtWidgets/QWidget>
#include "ui_GameFixSettingsWidget.h"
class SettingsDialog;
class GameFixSettingsWidget : public QWidget
{
Q_OBJECT
public:
GameFixSettingsWidget(QWidget* parent, SettingsDialog* dialog);
~GameFixSettingsWidget();
private:
Ui::GameFixSettingsWidget m_ui;
};

View File

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GameFixSettingsWidget</class>
<widget class="QWidget" name="GameFixSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>648</width>
<height>481</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Game Fixes (NOT recommended to change globally)</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="FpuNegDivHack">
<property name="text">
<string>FPU Negative Divide Hack (For Gundam Games)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="FpuMulHack">
<property name="text">
<string>FPU Multiply Hack (For Tales of Destiny)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="SoftwareRendererFMVHack">
<property name="text">
<string>Use Software Renderer For FMVs</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="SkipMPEGHack">
<property name="text">
<string>Skip MPEG Hack (Skips Videos/FMVs)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="GoemonTlbHack">
<property name="text">
<string>Preload TLB Hack (For Goemon)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="EETimingHack">
<property name="text">
<string>EE Timing Hack (General Purpose Timing Hack)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="OPHFlagHack">
<property name="text">
<string>OPH Flag Hack (For Bleach Blade Battlers)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="GIFFIFOHack">
<property name="text">
<string>Emulate GIF FIFO (Correct But Slower)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="DMABusyHack">
<property name="text">
<string>DMA Busy Hack (Deny Writes When Busy)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="VIF1StallHack">
<property name="text">
<string>Delay VIF1 Stalls (For SOCOM 2 HUD/Spy Hunter)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="VIFFIFOHack">
<property name="text">
<string>Emulate VIF FIFO (Correct But Slower)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="IbitHack">
<property name="text">
<string>VU I Bit Hack (For Scarface The World is Yours/Crash Tag Team Racing)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="VuAddSubHack">
<property name="text">
<string>VU Add Hack (For Tri-Ace Games)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="VUOverflowHack">
<property name="text">
<string>VU Overflow Hack (Superman Returns)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="VUKickstartHack">
<property name="text">
<string>VU Kickstart Hack (Run Ahead)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="XgKickHack">
<property name="text">
<string>VU XGKick Sync (Correct But Slower)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,244 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include <QtCore/QAbstractTableModel>
#include <QtCore/QDebug>
#include <QtCore/QSettings>
#include <QtCore/QUrl>
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMenu>
#include <QtWidgets/QMessageBox>
#include <algorithm>
#include "GameListSettingsWidget.h"
#include "MainWindow.h"
#include "QtHost.h"
#include "QtUtils.h"
GameListSettingsWidget::GameListSettingsWidget(QWidget* parent, SettingsDialog* dialog)
: QWidget(parent)
{
m_ui.setupUi(this);
m_ui.searchDirectoryList->setSelectionMode(QAbstractItemView::SingleSelection);
m_ui.searchDirectoryList->setSelectionBehavior(QAbstractItemView::SelectRows);
m_ui.searchDirectoryList->setAlternatingRowColors(true);
m_ui.searchDirectoryList->setShowGrid(false);
m_ui.searchDirectoryList->horizontalHeader()->setHighlightSections(false);
m_ui.searchDirectoryList->verticalHeader()->hide();
m_ui.searchDirectoryList->setCurrentIndex({});
m_ui.searchDirectoryList->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
connect(m_ui.searchDirectoryList, &QTableWidget::customContextMenuRequested, this,
&GameListSettingsWidget::onDirectoryListContextMenuRequested);
connect(m_ui.addSearchDirectoryButton, &QPushButton::clicked, this,
&GameListSettingsWidget::onAddSearchDirectoryButtonClicked);
connect(m_ui.removeSearchDirectoryButton, &QPushButton::clicked, this,
&GameListSettingsWidget::onRemoveSearchDirectoryButtonClicked);
connect(m_ui.addExcludedPath, &QPushButton::clicked, this, &GameListSettingsWidget::onAddExcludedPathButtonClicked);
connect(m_ui.removeExcludedPath, &QPushButton::clicked, this,
&GameListSettingsWidget::onRemoveExcludedPathButtonClicked);
connect(m_ui.rescanAllGames, &QPushButton::clicked, this, &GameListSettingsWidget::onRescanAllGamesClicked);
connect(m_ui.scanForNewGames, &QPushButton::clicked, this, &GameListSettingsWidget::onScanForNewGamesClicked);
refreshDirectoryList();
refreshExclusionList();
}
GameListSettingsWidget::~GameListSettingsWidget() = default;
bool GameListSettingsWidget::addExcludedPath(const std::string& path)
{
if (!QtHost::AddBaseValueToStringList("GameList", "ExcludedPaths", path.c_str()))
return false;
m_ui.excludedPaths->addItem(QString::fromStdString(path));
g_main_window->refreshGameList(false);
return true;
}
void GameListSettingsWidget::refreshExclusionList()
{
m_ui.excludedPaths->clear();
const std::vector<std::string> paths(QtHost::GetBaseStringListSetting("GameList", "ExcludedPaths"));
for (const std::string& path : paths)
m_ui.excludedPaths->addItem(QString::fromStdString(path));
}
void GameListSettingsWidget::resizeEvent(QResizeEvent* event)
{
QWidget::resizeEvent(event);
QtUtils::ResizeColumnsForTableView(m_ui.searchDirectoryList, {-1, 100});
}
void GameListSettingsWidget::addPathToTable(const std::string& path, bool recursive)
{
const int row = m_ui.searchDirectoryList->rowCount();
m_ui.searchDirectoryList->insertRow(row);
QTableWidgetItem* item = new QTableWidgetItem();
item->setText(QString::fromStdString(path));
m_ui.searchDirectoryList->setItem(row, 0, item);
QCheckBox* cb = new QCheckBox(m_ui.searchDirectoryList);
m_ui.searchDirectoryList->setCellWidget(row, 1, cb);
cb->setChecked(recursive);
connect(cb, &QCheckBox::stateChanged, [this, item](int state) {
const std::string path(item->text().toStdString());
if (state == Qt::Checked)
{
QtHost::RemoveBaseValueFromStringList("GameList", "Paths", path.c_str());
QtHost::AddBaseValueToStringList("GameList", "RecursivePaths", path.c_str());
}
else
{
QtHost::RemoveBaseValueFromStringList("GameList", "RecursivePaths", path.c_str());
QtHost::AddBaseValueToStringList("GameList", "Paths", path.c_str());
}
});
}
void GameListSettingsWidget::refreshDirectoryList()
{
QSignalBlocker sb(m_ui.searchDirectoryList);
while (m_ui.searchDirectoryList->rowCount() > 0)
m_ui.searchDirectoryList->removeRow(0);
std::vector<std::string> path_list = QtHost::GetBaseStringListSetting("GameList", "Paths");
for (const std::string& entry : path_list)
addPathToTable(entry, false);
path_list = QtHost::GetBaseStringListSetting("GameList", "RecursivePaths");
for (const std::string& entry : path_list)
addPathToTable(entry, true);
m_ui.searchDirectoryList->sortByColumn(0, Qt::AscendingOrder);
}
void GameListSettingsWidget::addSearchDirectory(const QString& path, bool recursive)
{
const std::string spath(path.toStdString());
QtHost::RemoveBaseValueFromStringList("GameList", recursive ? "Paths" : "RecursivePaths", spath.c_str());
QtHost::AddBaseValueToStringList("GameList", recursive ? "RecursivePaths" : "Paths", spath.c_str());
refreshDirectoryList();
g_main_window->refreshGameList(false);
}
void GameListSettingsWidget::removeSearchDirectory(const QString& path)
{
const std::string spath(path.toStdString());
if (!QtHost::RemoveBaseValueFromStringList("GameList", "Paths", spath.c_str()) &&
!QtHost::RemoveBaseValueFromStringList("GameList", "RecursivePaths", spath.c_str()))
{
return;
}
refreshDirectoryList();
g_main_window->refreshGameList(false);
}
void GameListSettingsWidget::onDirectoryListContextMenuRequested(const QPoint& point)
{
QModelIndexList selection = m_ui.searchDirectoryList->selectionModel()->selectedIndexes();
if (selection.size() < 1)
return;
const int row = selection[0].row();
QMenu menu;
menu.addAction(tr("Remove"), [this]() { onRemoveSearchDirectoryButtonClicked(); });
menu.addSeparator();
menu.addAction(tr("Open Directory..."), [this, row]() {
QtUtils::OpenURL(this, QUrl::fromLocalFile(m_ui.searchDirectoryList->item(row, 0)->text()));
});
menu.exec(m_ui.searchDirectoryList->mapToGlobal(point));
}
void GameListSettingsWidget::addSearchDirectory(QWidget* parent_widget)
{
QString dir =
QDir::toNativeSeparators(QFileDialog::getExistingDirectory(parent_widget, tr("Select Search Directory")));
if (dir.isEmpty())
return;
QMessageBox::StandardButton selection =
QMessageBox::question(this, tr("Scan Recursively?"),
tr("Would you like to scan the directory \"%1\" recursively?\n\nScanning recursively takes "
"more time, but will identify files in subdirectories.")
.arg(dir),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (selection == QMessageBox::Cancel)
return;
const bool recursive = (selection == QMessageBox::Yes);
addSearchDirectory(dir, recursive);
}
void GameListSettingsWidget::onAddSearchDirectoryButtonClicked()
{
addSearchDirectory(this);
}
void GameListSettingsWidget::onRemoveSearchDirectoryButtonClicked()
{
const int row = m_ui.searchDirectoryList->currentRow();
QTableWidgetItem* item = (row >= 0) ? m_ui.searchDirectoryList->takeItem(row, 0) : nullptr;
if (!item)
return;
removeSearchDirectory(item->text());
delete item;
}
void GameListSettingsWidget::onAddExcludedPathButtonClicked()
{
QString path =
QDir::toNativeSeparators(QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("Select Path")));
if (path.isEmpty())
return;
addExcludedPath(path.toStdString());
}
void GameListSettingsWidget::onRemoveExcludedPathButtonClicked()
{
const int row = m_ui.excludedPaths->currentRow();
QListWidgetItem* item = (row >= 0) ? m_ui.excludedPaths->takeItem(row) : 0;
if (!item)
return;
QtHost::RemoveBaseValueFromStringList("GameList", "ExcludedPaths", item->text().toUtf8().constData());
delete item;
g_main_window->refreshGameList(false);
}
void GameListSettingsWidget::onRescanAllGamesClicked()
{
g_main_window->refreshGameList(true);
}
void GameListSettingsWidget::onScanForNewGamesClicked()
{
g_main_window->refreshGameList(false);
}

View File

@ -0,0 +1,59 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <QtWidgets/QWidget>
#include "ui_GameListSettingsWidget.h"
class SettingsDialog;
class GameListSearchDirectoriesModel;
class GameListSettingsWidget : public QWidget
{
Q_OBJECT
public:
GameListSettingsWidget(QWidget* parent, SettingsDialog* dialog);
~GameListSettingsWidget();
bool addExcludedPath(const std::string& path);
void refreshExclusionList();
public Q_SLOTS:
void addSearchDirectory(QWidget* parent_widget);
private Q_SLOTS:
void onDirectoryListContextMenuRequested(const QPoint& point);
void onAddSearchDirectoryButtonClicked();
void onRemoveSearchDirectoryButtonClicked();
void onAddExcludedPathButtonClicked();
void onRemoveExcludedPathButtonClicked();
void onScanForNewGamesClicked();
void onRescanAllGamesClicked();
protected:
void resizeEvent(QResizeEvent* event);
private:
void addPathToTable(const std::string& path, bool recursive);
void refreshDirectoryList();
void addSearchDirectory(const QString& path, bool recursive);
void removeSearchDirectory(const QString& path);
Ui::GameListSettingsWidget m_ui;
};

View File

@ -0,0 +1,213 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GameListSettingsWidget</class>
<widget class="QWidget" name="GameListSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>532</width>
<height>376</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,2,0,1,0">
<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>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Search Directories (will be scanned for games)</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="addSearchDirectoryButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Add</string>
</property>
<property name="icon">
<iconset theme="folder-add-line" />
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="removeSearchDirectoryButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Remove</string>
</property>
<property name="icon">
<iconset theme="folder-reduce-line" />
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="searchDirectoryList">
<column>
<property name="text">
<string>Search Directory</string>
</property>
</column>
<column>
<property name="text">
<string>Scan Recursively</string>
</property>
</column>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Excluded Paths (will not be scanned)</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="addExcludedPath">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Add</string>
</property>
<property name="icon">
<iconset theme="file-add-line" />
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="removeExcludedPath">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Remove</string>
</property>
<property name="icon">
<iconset theme="file-reduce-line" />
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="excludedPaths"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="scanForNewGames">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Scan For New Games</string>
</property>
<property name="icon">
<iconset theme="file-search-line" />
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="rescanAllGames">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Rescan All Games</string>
</property>
<property name="icon">
<iconset theme="refresh-line" />
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,381 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "GraphicsSettingsWidget.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#include "SettingsDialog.h"
#include <QtWidgets/QMessageBox>
#include "pcsx2/GS/GS.h"
#include "pcsx2/GS/GSUtil.h"
#include "Frontend/VulkanHostDisplay.h"
#ifdef _WIN32
#include "Frontend/D3D11HostDisplay.h"
#endif
struct RendererInfo
{
const char* name;
GSRendererType type;
};
static constexpr RendererInfo s_renderer_info[] = {
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Automatic"),
GSRendererType::Auto,
#ifdef _WIN32
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Direct3D 11"),
GSRendererType::DX11,
#endif
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "OpenGL"),
GSRendererType::OGL,
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Vulkan"),
GSRendererType::VK,
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Software"),
GSRendererType::SW,
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Null"),
GSRendererType::Null,
};
static const char* s_anisotropic_filtering_entries[] = {QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Off (Default)"),
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "2x"),
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "4x"),
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "8x"),
QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "16x"),
nullptr};
static const char* s_anisotropic_filtering_values[] = {"1", "2", "4", "8", "16", nullptr};
static constexpr int DEFAULT_INTERLACE_MODE = 7;
GraphicsSettingsWidget::GraphicsSettingsWidget(QWidget* parent, SettingsDialog* dialog)
: QWidget(parent)
{
m_ui.setupUi(this);
//////////////////////////////////////////////////////////////////////////
// Global Settings
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToStringSetting(m_ui.adapter, "EmuCore/GS", "Adapter");
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.vsync, "EmuCore/GS", "VsyncEnable", 0);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.enableHWFixes, "EmuCore/GS", "UserHacks", false);
//////////////////////////////////////////////////////////////////////////
// Game Display Settings
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToEnumSetting(m_ui.aspectRatio, "EmuCore/GS", "AspectRatio",
Pcsx2Config::GSOptions::AspectRatioNames, AspectRatioType::R4_3);
SettingWidgetBinder::BindWidgetToEnumSetting(m_ui.fmvAspectRatio, "EmuCore/GS", "FMVAspectRatioSwitch",
Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames,
FMVAspectRatioSwitchType::Off);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.interlacing, "EmuCore/GS", "interlace", DEFAULT_INTERLACE_MODE);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.bilinearFiltering, "EmuCore/GS", "LinearPresent", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.integerScaling, "EmuCore/GS", "IntegerScaling", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.internalResolutionScreenshots, "EmuCore/GS",
"InternalResolutionScreenshots", false);
SettingWidgetBinder::BindWidgetToFloatSetting(m_ui.zoom, "EmuCore/GS", "Zoom", 100.0f);
SettingWidgetBinder::BindWidgetToFloatSetting(m_ui.stretchY, "EmuCore/GS", "StretchY", 100.0f);
SettingWidgetBinder::BindWidgetToFloatSetting(m_ui.offsetX, "EmuCore/GS", "OffsetX", 0.0f);
SettingWidgetBinder::BindWidgetToFloatSetting(m_ui.offsetY, "EmuCore/GS", "OffsetY", 0.0f);
connect(m_ui.integerScaling, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onIntegerScalingChanged);
onIntegerScalingChanged();
connect(m_ui.fullscreenModes, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::onFullscreenModeChanged);
//////////////////////////////////////////////////////////////////////////
// OSD Settings
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToFloatSetting(m_ui.osdScale, "EmuCore/GS", "OsdScale", 100.0f);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.osdShowMessages, "EmuCore/GS", "OsdShowMessages", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.osdShowSpeed, "EmuCore/GS", "OsdShowSpeed", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.osdShowFPS, "EmuCore/GS", "OsdShowFPS", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.osdShowCPU, "EmuCore/GS", "OsdShowCPU", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.osdShowResolution, "EmuCore/GS", "OsdShowResolution", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.osdShowGSStats, "EmuCore/GS", "OsdShowGSStats", false);
dialog->registerWidgetHelp(m_ui.osdShowMessages, tr("Show OSD Messages"), tr("Checked"),
tr("Shows on-screen-display messages when events occur such as save states being "
"created/loaded, screenshots being taken, etc."));
dialog->registerWidgetHelp(m_ui.osdShowFPS, tr("Show Game Frame Rate"), tr("Unchecked"),
tr("Shows the internal frame rate of the game in the top-right corner of the display."));
dialog->registerWidgetHelp(
m_ui.osdShowSpeed, tr("Show Emulation Speed"), tr("Unchecked"),
tr("Shows the current emulation speed of the system in the top-right corner of the display as a percentage."));
dialog->registerWidgetHelp(m_ui.osdShowResolution, tr("Show Resolution"), tr("Unchecked"),
tr("Shows the resolution of the game in the top-right corner of the display."));
//////////////////////////////////////////////////////////////////////////
// HW Settings
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.upscaleMultiplier, "EmuCore/GS", "upscale_multiplier", 1);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.textureFiltering, "EmuCore/GS", "filter",
static_cast<int>(BiFiltering::PS2));
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.trilinearFiltering, "EmuCore/GS", "UserHacks_TriFilter",
static_cast<int>(TriFiltering::Off));
SettingWidgetBinder::BindWidgetToEnumSetting(m_ui.anisotropicFiltering, "EmuCore/GS", "MaxAnisotropy",
s_anisotropic_filtering_entries, s_anisotropic_filtering_values, "1");
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.dithering, "EmuCore/GS", "dithering_ps2", 2);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.mipmapping, "EmuCore/GS", "mipmap_hw",
static_cast<int>(HWMipmapLevel::Automatic), -1);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level",
static_cast<int>(CRCHackLevel::Automatic), -1);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.blending, "EmuCore/GS", "accurate_blending_unit",
static_cast<int>(AccBlendLevel::Basic));
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.accurateDATE, "EmuCore/GS", "accurate_date", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.conservativeBufferAllocation, "EmuCore/GS",
"conservative_framebuffer", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.gpuPaletteConversion, "EmuCore/GS", "paltex", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.preloadTexture, "EmuCore/GS", "preload_texture", false);
//////////////////////////////////////////////////////////////////////////
// HW Renderer Fixes
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.halfScreenFix, "EmuCore/GS", "UserHacks_Half_Bottom_Override", -1,
-1);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.skipDrawRangeStart, "EmuCore/GS", "UserHacks_SkipDraw", 0);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.skipDrawRangeCount, "EmuCore/GS", "UserHacks_SkipDraw_Offset", 0);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.hwAutoFlush, "EmuCore/GS", "UserHacks_AutoFlush", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.frameBufferConversion, "EmuCore/GS", "UserHacks_CPU_FB_Conversion",
false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.disableDepthEmulation, "EmuCore/GS",
"UserHacks_DisableDepthSupport", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.memoryWrapping, "EmuCore/GS", "wrap_gs_mem", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.disableSafeFeatures, "EmuCore/GS",
"UserHacks_Disable_Safe_Features", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.preloadFrameData, "EmuCore/GS", "preload_frame_with_gs_data",
false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.fastTextureInvalidation, "EmuCore/GS",
"UserHacks_DisablePartialInvalidation", false);
//////////////////////////////////////////////////////////////////////////
// HW Upscaling Fixes
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.halfPixelOffset, "EmuCore/GS", "UserHacks_HalfPixelOffset", 0);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.roundSprite, "EmuCore/GS", "UserHacks_RoundSprite", 0);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.textureOffsetX, "EmuCore/GS", "UserHacks_TCOffsetX", 0);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.textureOffsetY, "EmuCore/GS", "UserHacks_TCOffsetY", 0);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.alignSprite, "EmuCore/GS", "UserHacks_align_sprite_X", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.mergeSprite, "EmuCore/GS", "UserHacks_merge_pp_sprite", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.wildHack, "EmuCore/GS", "UserHacks_WildHack", false);
//////////////////////////////////////////////////////////////////////////
// Advanced Settings
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.useBlitSwapChain, "EmuCore/GS", "UseBlitSwapChain", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.useDebugDevice, "EmuCore/GS", "UseDebugDevice", false);
//////////////////////////////////////////////////////////////////////////
// SW Settings
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.extraSWThreads, "EmuCore/GS", "extrathreads", 2);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.swAutoFlush, "EmuCore/GS", "autoflush_sw", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.swAA1, "EmuCore/GS", "aa1", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.swMipmap, "EmuCore/GS", "mipmap", true);
//////////////////////////////////////////////////////////////////////////
// Non-trivial settings
//////////////////////////////////////////////////////////////////////////
const GSRendererType current_renderer = static_cast<GSRendererType>(
QtHost::GetBaseIntSettingValue("EmuCore/GS", "Renderer", static_cast<int>(GSRendererType::Auto)));
for (const RendererInfo& ri : s_renderer_info)
{
m_ui.renderer->addItem(qApp->translate("GraphicsSettingsWidget", ri.name));
if (ri.type == current_renderer)
m_ui.renderer->setCurrentIndex(m_ui.renderer->count() - 1);
}
connect(m_ui.renderer, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::onRendererChanged);
connect(m_ui.enableHWFixes, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onEnableHardwareFixesChanged);
updateRendererDependentOptions();
dialog->registerWidgetHelp(m_ui.useBlitSwapChain, tr("Use Blit Swap Chain"), tr("Unchecked"),
tr("Uses a blit presentation model instead of flipping when using the Direct3D 11 "
"renderer. This usually results in slower performance, but may be required for some "
"streaming applications, or to uncap framerates on some systems."));
}
GraphicsSettingsWidget::~GraphicsSettingsWidget() = default;
void GraphicsSettingsWidget::onRendererChanged(int index)
{
QtHost::SetBaseIntSettingValue("EmuCore/GS", "Renderer", static_cast<int>(s_renderer_info[index].type));
g_emu_thread->applySettings();
updateRendererDependentOptions();
}
void GraphicsSettingsWidget::onAdapterChanged(int index)
{
if (index == 0)
QtHost::RemoveBaseSettingValue("EmuCore/GS", "Adapter");
else
QtHost::SetBaseStringSettingValue("EmuCore/GS", "Adapter", m_ui.adapter->currentText().toUtf8().constData());
g_emu_thread->applySettings();
}
void GraphicsSettingsWidget::onEnableHardwareFixesChanged()
{
const bool enabled = m_ui.enableHWFixes->isChecked();
m_ui.hardwareRendererGroup->setTabEnabled(2, enabled);
m_ui.hardwareRendererGroup->setTabEnabled(3, enabled);
}
void GraphicsSettingsWidget::updateRendererDependentOptions()
{
const int index = m_ui.renderer->currentIndex();
GSRendererType type = s_renderer_info[index].type;
if (type == GSRendererType::Auto)
type = GSUtil::GetPreferredRenderer();
#ifdef _WIN32
const bool is_dx11 = (type == GSRendererType::DX11 || type == GSRendererType::SW);
#else
const bool is_dx11 = false;
#endif
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::OGL || type == GSRendererType::VK);
const bool is_software = (type == GSRendererType::SW);
// move advanced tab to the correct parent
static constexpr std::array<const char*, 3> move_tab_names = {{"Display", "On-Screen Display", "Advanced"}};
const std::array<QWidget*, 3> move_tab_pointers = {{m_ui.gameDisplayTab, m_ui.osdTab, m_ui.advancedTab}};
for (size_t i = 0; i < move_tab_pointers.size(); i++)
{
QWidget* tab = move_tab_pointers[i];
const QString tab_label(tr(move_tab_names[i]));
if (const int index = m_ui.softwareRendererGroup->indexOf(tab); index >= 0 && is_hardware)
m_ui.softwareRendererGroup->removeTab(index);
if (const int index = m_ui.hardwareRendererGroup->indexOf(tab); index >= 0 && is_software)
m_ui.hardwareRendererGroup->removeTab(index);
if (const int index = m_ui.hardwareRendererGroup->indexOf(tab); index < 0 && is_hardware)
m_ui.hardwareRendererGroup->insertTab((i == 0) ? 0 : m_ui.hardwareRendererGroup->count(), tab, tab_label);
if (const int index = m_ui.softwareRendererGroup->indexOf(tab); index < 0 && is_software)
m_ui.softwareRendererGroup->insertTab((i == 0) ? 0 : m_ui.softwareRendererGroup->count(), tab, tab_label);
}
if (is_hardware != is_software)
{
if (is_hardware)
m_ui.hardwareRendererGroup->setCurrentIndex(0);
else
m_ui.softwareRendererGroup->setCurrentIndex(0);
}
if (m_hardware_renderer_visible != is_hardware)
{
m_ui.hardwareRendererGroup->setVisible(is_hardware);
if (!is_hardware)
m_ui.verticalLayout->removeWidget(m_ui.hardwareRendererGroup);
else
m_ui.verticalLayout->insertWidget(1, m_ui.hardwareRendererGroup);
m_hardware_renderer_visible = is_hardware;
}
if (m_software_renderer_visible != is_software)
{
m_ui.softwareRendererGroup->setVisible(is_software);
if (!is_hardware)
m_ui.verticalLayout->removeWidget(m_ui.softwareRendererGroup);
else
m_ui.verticalLayout->insertWidget(1, m_ui.softwareRendererGroup);
m_software_renderer_visible = is_software;
}
m_ui.useBlitSwapChain->setEnabled(is_dx11);
// populate adapters
HostDisplay::AdapterAndModeList modes;
switch (type)
{
#ifdef _WIN32
case GSRendererType::DX11:
modes = D3D11HostDisplay::StaticGetAdapterAndModeList();
break;
#endif
case GSRendererType::VK:
modes = VulkanHostDisplay::StaticGetAdapterAndModeList(nullptr);
break;
case GSRendererType::OGL:
case GSRendererType::SW:
case GSRendererType::Null:
case GSRendererType::Auto:
default:
break;
}
// fill+select adapters
{
const std::string current_adapter = QtHost::GetBaseStringSettingValue("EmuCore/GS", "Adapter", "");
QSignalBlocker sb(m_ui.adapter);
m_ui.adapter->clear();
m_ui.adapter->setEnabled(!modes.adapter_names.empty());
m_ui.adapter->addItem(tr("(Default)"));
for (const std::string& adapter : modes.adapter_names)
{
m_ui.adapter->addItem(QString::fromStdString(adapter));
if (current_adapter == adapter)
m_ui.adapter->setCurrentIndex(m_ui.adapter->count() - 1);
}
}
// fill+select fullscreen modes
{
QSignalBlocker sb(m_ui.fullscreenModes);
const std::string current_mode(QtHost::GetBaseStringSettingValue("EmuCore/GS", "FullscreenMode", ""));
m_ui.fullscreenModes->clear();
m_ui.fullscreenModes->addItem(tr("Borderless Fullscreen"));
if (current_mode.empty())
m_ui.fullscreenModes->setCurrentIndex(0);
for (const std::string& fs_mode : modes.fullscreen_modes)
{
m_ui.fullscreenModes->addItem(QString::fromStdString(fs_mode));
if (current_mode == fs_mode)
m_ui.fullscreenModes->setCurrentIndex(m_ui.fullscreenModes->count() - 1);
}
}
m_ui.enableHWFixes->setEnabled(is_hardware);
onEnableHardwareFixesChanged();
}
void GraphicsSettingsWidget::onIntegerScalingChanged()
{
m_ui.bilinearFiltering->setEnabled(!m_ui.integerScaling->isChecked());
}
void GraphicsSettingsWidget::onFullscreenModeChanged(int index)
{
if (index == 0)
{
QtHost::RemoveBaseSettingValue("EmuCore/GS", "FullscreenMode");
}
else
{
QtHost::SetBaseStringSettingValue("EmuCore/GS", "FullscreenMode",
m_ui.fullscreenModes->currentText().toUtf8().constData());
}
g_emu_thread->applySettings();
}

View File

@ -0,0 +1,49 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtWidgets/QWidget>
#include "ui_GraphicsSettingsWidget.h"
class SettingsDialog;
class GraphicsSettingsWidget : public QWidget
{
Q_OBJECT
public:
GraphicsSettingsWidget(QWidget* parent, SettingsDialog* dialog);
~GraphicsSettingsWidget();
void updateRendererDependentOptions();
Q_SIGNALS:
void fullscreenModesChanged(const QStringList& modes);
private Q_SLOTS:
void onRendererChanged(int index);
void onAdapterChanged(int index);
void onEnableHardwareFixesChanged();
void onIntegerScalingChanged();
void onFullscreenModeChanged(int index);
private:
Ui::GraphicsSettingsWidget m_ui;
bool m_hardware_renderer_visible = true;
bool m_software_renderer_visible = true;
};

View File

@ -0,0 +1,997 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GraphicsSettingsWidget</class>
<widget class="QWidget" name="GraphicsSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>747</width>
<height>890</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Renderer</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Renderer:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="renderer"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Adapter:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="adapter"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTabWidget" name="hardwareRendererGroup">
<property name="currentIndex">
<number>0</number>
</property>
<property name="documentMode">
<bool>true</bool>
</property>
<widget class="QGroupBox" name="gameDisplayTab">
<attribute name="title">
<string>Display</string>
</attribute>
<layout class="QFormLayout" name="formLayout_7">
<item row="0" column="0">
<widget class="QLabel" name="label_28">
<property name="text">
<string>Fullscreen Mode:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="fullscreenModes"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
<string>Aspect Ratio:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="aspectRatio">
<item>
<property name="text">
<string>Fit to Window/Screen</string>
</property>
</item>
<item>
<property name="text">
<string>Standard (4:3)</string>
</property>
</item>
<item>
<property name="text">
<string>Widescreen (16:9)</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>FMV Aspect Ratio:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="fmvAspectRatio">
<item>
<property name="text">
<string>Off (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Standard (4:3)</string>
</property>
</item>
<item>
<property name="text">
<string>Widescreen (16:9)</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Interlacing:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="interlacing">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Weave (Top Field First, Sawtooth)</string>
</property>
</item>
<item>
<property name="text">
<string>Weave (Bottom Field First, Sawtooth)</string>
</property>
</item>
<item>
<property name="text">
<string>Bob (Top Field First)</string>
</property>
</item>
<item>
<property name="text">
<string>Bob (Bottom Field First)</string>
</property>
</item>
<item>
<property name="text">
<string>Blend (Top Field First, Half FPS)</string>
</property>
</item>
<item>
<property name="text">
<string>Blend (Bottom Field First, Half FPS)</string>
</property>
</item>
<item>
<property name="text">
<string>Automatic (Default)</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Zoom:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="zoom">
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>300</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Stretch Height:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="stretchY">
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>300</number>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Offset:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,0,1">
<item>
<widget class="QSpinBox" name="offsetX">
<property name="suffix">
<string>px</string>
</property>
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_25">
<property name="text">
<string>x</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="offsetY">
<property name="suffix">
<string>px</string>
</property>
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="7" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="2">
<widget class="QCheckBox" name="integerScaling">
<property name="text">
<string>Integer Upscaling</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="bilinearFiltering">
<property name="text">
<string>Bilinear Filtering</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="vsync">
<property name="text">
<string>Sync To Host Refresh (VSync)</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="internalResolutionScreenshots">
<property name="text">
<string>Internal Resolution Screenshots</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="hardwareRenderingTab">
<attribute name="title">
<string>Rendering</string>
</attribute>
<layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Internal Resolution:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="upscaleMultiplier">
<item>
<property name="text">
<string>Custom</string>
</property>
</item>
<item>
<property name="text">
<string>Native (PS2)</string>
</property>
</item>
<item>
<property name="text">
<string>2x Native (~720p)</string>
</property>
</item>
<item>
<property name="text">
<string>3x Native (~1080p)</string>
</property>
</item>
<item>
<property name="text">
<string>4x Native (~1440p/2K)</string>
</property>
</item>
<item>
<property name="text">
<string>5x Native (~1620p)</string>
</property>
</item>
<item>
<property name="text">
<string>6x Native (~2160p/4K)</string>
</property>
</item>
<item>
<property name="text">
<string>7x Native (~2520p)</string>
</property>
</item>
<item>
<property name="text">
<string>8x Native (~2280p)</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Mipmapping:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mipmapping">
<item>
<property name="text">
<string>Automatic (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Off</string>
</property>
</item>
<item>
<property name="text">
<string>Basic (Generated Mipmaps)</string>
</property>
</item>
<item>
<property name="text">
<string>Full (PS2 Mipmaps)</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Texture Filtering:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="textureFiltering">
<item>
<property name="text">
<string>Nearest</string>
</property>
</item>
<item>
<property name="text">
<string>Bilinear (Forced)</string>
</property>
</item>
<item>
<property name="text">
<string>Bilinear (PS2)</string>
</property>
</item>
<item>
<property name="text">
<string>Bilinear (Forced excluding sprite)</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Trilinear Filtering:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="trilinearFiltering">
<item>
<property name="text">
<string>None (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Trilinear (PS2)</string>
</property>
</item>
<item>
<property name="text">
<string>Trilinear (Forced)</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Anisotropic Filtering:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="anisotropicFiltering"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Dithering:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="dithering">
<item>
<property name="text">
<string>Off</string>
</property>
</item>
<item>
<property name="text">
<string>Scaled</string>
</property>
</item>
<item>
<property name="text">
<string>Unscaled (Default)</string>
</property>
</item>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>CRC Fix Level:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="crcFixLevel">
<item>
<property name="text">
<string>Automatic (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>None (Debug)</string>
</property>
</item>
<item>
<property name="text">
<string>Minimum (Debug)</string>
</property>
</item>
<item>
<property name="text">
<string>Partial (OpenGL)</string>
</property>
</item>
<item>
<property name="text">
<string>Full (Direct3D)</string>
</property>
</item>
<item>
<property name="text">
<string>Aggressive</string>
</property>
</item>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Blending Accuracy:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QComboBox" name="blending">
<item>
<property name="text">
<string>Minimum (Fastest)</string>
</property>
</item>
<item>
<property name="text">
<string>Basic (Recommended)</string>
</property>
</item>
<item>
<property name="text">
<string>Medium</string>
</property>
</item>
<item>
<property name="text">
<string>High</string>
</property>
</item>
<item>
<property name="text">
<string>Full (Very Slow)</string>
</property>
</item>
<item>
<property name="text">
<string>Ultra (Ultra Slow)</string>
</property>
</item>
</widget>
</item>
<item row="8" column="0" colspan="2">
<layout class="QGridLayout" name="basicCheckboxGridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="accurateDATE">
<property name="text">
<string>Accurate Destination Alpha Test</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="conservativeBufferAllocation">
<property name="text">
<string>Conservative Buffer Allocation</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="gpuPaletteConversion">
<property name="text">
<string>GPU Palette Conversion</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="preloadTexture">
<property name="text">
<string>Preload Textures</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="enableHWFixes">
<property name="text">
<string>Enable Hardware Renderer Fixes</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="hardwareFixesTab">
<attribute name="title">
<string>Hardware Fixes</string>
</attribute>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Half Screen Fix:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="halfScreenFix">
<item>
<property name="text">
<string>Automatic (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Force Disabled</string>
</property>
</item>
<item>
<property name="text">
<string>Force Enabled</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Skipdraw Range:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSpinBox" name="skipDrawRangeStart"/>
</item>
<item>
<widget class="QSpinBox" name="skipDrawRangeCount"/>
</item>
</layout>
</item>
<item row="2" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="hwAutoFlush">
<property name="text">
<string>Auto Flush</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="frameBufferConversion">
<property name="text">
<string>Frame Buffer Conversion</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="disableDepthEmulation">
<property name="text">
<string>Disable Depth Emulation</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="memoryWrapping">
<property name="text">
<string>Memory Wrapping</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="disableSafeFeatures">
<property name="text">
<string>Disable Safe Features</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="preloadFrameData">
<property name="text">
<string>Preload Frame Data</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="fastTextureInvalidation">
<property name="text">
<string>Fast Texture Invalidation</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="upscalingFixesTab">
<attribute name="title">
<string>Upscaling Fixes</string>
</attribute>
<layout class="QFormLayout" name="formLayout_5">
<item row="0" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Half Pixel Offset:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="halfPixelOffset">
<item>
<property name="text">
<string>Off (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Normal (Vertex)</string>
</property>
</item>
<item>
<property name="text">
<string>Special (Texture)</string>
</property>
</item>
<item>
<property name="text">
<string>Special (Texture - Aggressive)</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Round Sprite:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="roundSprite">
<item>
<property name="text">
<string>Off (Default</string>
</property>
</item>
<item>
<property name="text">
<string>Half</string>
</property>
</item>
<item>
<property name="text">
<string>Full</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Texture Offsets:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,1,0,1">
<item>
<widget class="QLabel" name="label_17">
<property name="text">
<string>X:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="textureOffsetX"/>
</item>
<item>
<widget class="QLabel" name="label_18">
<property name="text">
<string>Y:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="textureOffsetY"/>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="1">
<widget class="QCheckBox" name="mergeSprite">
<property name="text">
<string>Merge Sprite</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="alignSprite">
<property name="text">
<string>Align Sprite</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="wildHack">
<property name="text">
<string>Wild Arms Hack</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="osdTab">
<attribute name="title">
<string>On-Screen Display</string>
</attribute>
<layout class="QFormLayout" name="formLayout_8">
<item row="0" column="0">
<widget class="QLabel" name="label_29">
<property name="text">
<string>OSD Scale:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="osdScale">
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>100</number>
</property>
<property name="maximum">
<number>500</number>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<widget class="QCheckBox" name="osdShowMessages">
<property name="text">
<string>Show Notifications</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="osdShowSpeed">
<property name="text">
<string>Show Speed</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="osdShowFPS">
<property name="text">
<string>Show FPS</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="osdShowResolution">
<property name="text">
<string>Show Resolution</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="osdShowCPU">
<property name="text">
<string>Show CPU Usage</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="osdShowGSStats">
<property name="text">
<string>Show Statistics</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="advancedTab">
<attribute name="title">
<string>Advanced</string>
</attribute>
<layout class="QFormLayout" name="formLayout_6">
<item row="0" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="useBlitSwapChain">
<property name="text">
<string>Use Blit Swap Chain</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="useDebugDevice">
<property name="text">
<string>Use Debug Device</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QTabWidget" name="softwareRendererGroup">
<property name="documentMode">
<bool>true</bool>
</property>
<widget class="QGroupBox" name="softwareRendererSettings">
<attribute name="title">
<string>Rendering</string>
</attribute>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Extra Rendering Threads:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="extraSWThreads">
<property name="suffix">
<string> threads</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="swAutoFlush">
<property name="text">
<string>Auto Flush</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="swMipmap">
<property name="text">
<string>Mipmapping</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="swAA1">
<property name="text">
<string>Edge Anti-Aliasing</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,84 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Frontend/InputManager.h"
#include "Settings/HotkeySettingsWidget.h"
#include "Settings/ControllerSettingsDialog.h"
#include "InputBindingWidget.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QLabel>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QScrollArea>
#include <QtWidgets/QTabWidget>
HotkeySettingsWidget::HotkeySettingsWidget(QWidget* parent, ControllerSettingsDialog* dialog)
: QWidget(parent)
{
createUi();
}
HotkeySettingsWidget::~HotkeySettingsWidget() = default;
void HotkeySettingsWidget::createUi()
{
QGridLayout* layout = new QGridLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
m_tab_widget = new QTabWidget(this);
createButtons();
layout->addWidget(m_tab_widget, 0, 0, 1, 1);
setLayout(layout);
}
void HotkeySettingsWidget::createButtons()
{
const std::vector<const HotkeyInfo*> hotkeys(InputManager::GetHotkeyList());
for (const HotkeyInfo* hotkey : hotkeys)
{
const auto category = qApp->translate("Hotkeys", hotkey->category);
auto iter = m_categories.find(category);
if (iter == m_categories.end())
{
QScrollArea* scroll = new QScrollArea(m_tab_widget);
QWidget* container = new QWidget(scroll);
QVBoxLayout* vlayout = new QVBoxLayout(container);
QGridLayout* layout = new QGridLayout();
layout->setContentsMargins(0, 0, 0, 0);
vlayout->addLayout(layout);
vlayout->addStretch(1);
iter = m_categories.insert(category, Category{container, layout});
scroll->setWidget(container);
scroll->setWidgetResizable(true);
scroll->setBackgroundRole(QPalette::Base);
scroll->setFrameShape(QFrame::NoFrame);
m_tab_widget->addTab(scroll, category);
}
QWidget* container = iter->container;
QGridLayout* layout = iter->layout;
const int target_row = layout->count() / 2;
layout->addWidget(new QLabel(qApp->translate("Hotkeys", hotkey->display_name), container), target_row, 0);
layout->addWidget(new InputBindingWidget(container, "Hotkeys", hotkey->name), target_row, 1);
}
}

View File

@ -0,0 +1,48 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtWidgets/QWidget>
#include <QtCore/QMap>
#include <array>
#include <vector>
class QTabWidget;
class QGridLayout;
class ControllerSettingsDialog;
class HotkeySettingsWidget : public QWidget
{
Q_OBJECT
public:
HotkeySettingsWidget(QWidget* parent, ControllerSettingsDialog* dialog);
~HotkeySettingsWidget();
private:
void createUi();
void createButtons();
QTabWidget* m_tab_widget;
struct Category
{
QWidget* container;
QGridLayout* layout;
};
QMap<QString, Category> m_categories;
};

View File

@ -0,0 +1,230 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "EmuThread.h"
#include "QtHost.h"
#include "Settings/InputBindingDialog.h"
#include <QtCore/QTimer>
#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
// _BitScanForward()
#include "pcsx2/GS/GSIntrin.h"
InputBindingDialog::InputBindingDialog(std::string section_name, std::string key_name,
std::vector<std::string> bindings, QWidget* parent)
: QDialog(parent)
, m_section_name(std::move(section_name))
, m_key_name(std::move(key_name))
, m_bindings(std::move(bindings))
{
m_ui.setupUi(this);
m_ui.title->setText(
tr("Bindings for %1 %2").arg(QString::fromStdString(m_section_name)).arg(QString::fromStdString(m_key_name)));
m_ui.buttonBox->button(QDialogButtonBox::Close)->setText(tr("Close"));
connect(m_ui.addBinding, &QPushButton::clicked, this, &InputBindingDialog::onAddBindingButtonClicked);
connect(m_ui.removeBinding, &QPushButton::clicked, this, &InputBindingDialog::onRemoveBindingButtonClicked);
connect(m_ui.clearBindings, &QPushButton::clicked, this, &InputBindingDialog::onClearBindingsButtonClicked);
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, [this]() { done(0); });
updateList();
}
InputBindingDialog::~InputBindingDialog()
{
Q_ASSERT(!isListeningForInput());
}
bool InputBindingDialog::eventFilter(QObject* watched, QEvent* event)
{
const QEvent::Type event_type = event->type();
// if the key is being released, set the input
if (event_type == QEvent::KeyRelease || event_type == QEvent::MouseButtonPress)
{
addNewBinding();
stopListeningForInput();
return true;
}
else if (event_type == QEvent::KeyPress)
{
const QKeyEvent* key_event = static_cast<const QKeyEvent*>(event);
m_new_bindings.push_back(InputManager::MakeHostKeyboardKey(key_event->key()));
return true;
}
else if (event_type == QEvent::MouseButtonPress)
{
unsigned long button_index;
if (_BitScanForward(&button_index, static_cast<u32>(static_cast<const QMouseEvent*>(event)->button())))
m_new_bindings.push_back(InputManager::MakeHostMouseButtonKey(button_index));
return true;
}
else if (event_type == QEvent::MouseButtonDblClick)
{
// just eat double clicks
return true;
}
return false;
}
void InputBindingDialog::onInputListenTimerTimeout()
{
m_input_listen_remaining_seconds--;
if (m_input_listen_remaining_seconds == 0)
{
stopListeningForInput();
return;
}
m_ui.status->setText(tr("Push Button/Axis... [%1]").arg(m_input_listen_remaining_seconds));
}
void InputBindingDialog::startListeningForInput(u32 timeout_in_seconds)
{
m_input_listen_timer = new QTimer(this);
m_input_listen_timer->setSingleShot(false);
m_input_listen_timer->start(1000);
m_input_listen_timer->connect(m_input_listen_timer, &QTimer::timeout, this,
&InputBindingDialog::onInputListenTimerTimeout);
m_input_listen_remaining_seconds = timeout_in_seconds;
m_ui.status->setText(tr("Push Button/Axis... [%1]").arg(m_input_listen_remaining_seconds));
m_ui.addBinding->setEnabled(false);
m_ui.removeBinding->setEnabled(false);
m_ui.clearBindings->setEnabled(false);
m_ui.buttonBox->setEnabled(false);
installEventFilter(this);
grabKeyboard();
grabMouse();
}
void InputBindingDialog::stopListeningForInput()
{
m_ui.status->clear();
m_ui.addBinding->setEnabled(true);
m_ui.removeBinding->setEnabled(true);
m_ui.clearBindings->setEnabled(true);
m_ui.buttonBox->setEnabled(true);
delete m_input_listen_timer;
m_input_listen_timer = nullptr;
releaseMouse();
releaseKeyboard();
removeEventFilter(this);
}
void InputBindingDialog::addNewBinding()
{
if (m_new_bindings.empty())
return;
const std::string new_binding(
InputManager::ConvertInputBindingKeysToString(m_new_bindings.data(), m_new_bindings.size()));
if (!new_binding.empty())
{
if (std::find(m_bindings.begin(), m_bindings.end(), new_binding) != m_bindings.end())
return;
m_ui.bindingList->addItem(QString::fromStdString(new_binding));
m_bindings.push_back(std::move(new_binding));
saveListToSettings();
}
}
void InputBindingDialog::onAddBindingButtonClicked()
{
if (isListeningForInput())
stopListeningForInput();
startListeningForInput(TIMEOUT_FOR_BINDING);
}
void InputBindingDialog::onRemoveBindingButtonClicked()
{
const int row = m_ui.bindingList->currentRow();
if (row < 0 || static_cast<size_t>(row) >= m_bindings.size())
return;
m_bindings.erase(m_bindings.begin() + row);
delete m_ui.bindingList->takeItem(row);
saveListToSettings();
}
void InputBindingDialog::onClearBindingsButtonClicked()
{
m_bindings.clear();
m_ui.bindingList->clear();
saveListToSettings();
}
void InputBindingDialog::updateList()
{
m_ui.bindingList->clear();
for (const std::string& binding : m_bindings)
m_ui.bindingList->addItem(QString::fromStdString(binding));
}
void InputBindingDialog::saveListToSettings()
{
if (!m_bindings.empty())
QtHost::SetBaseStringListSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_bindings);
else
QtHost::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
g_emu_thread->reloadInputBindings();
}
void InputBindingDialog::inputManagerHookCallback(InputBindingKey key, float value)
{
for (InputBindingKey other_key : m_new_bindings)
{
if (other_key.MaskDirection() == key.MaskDirection())
{
if (value < 0.25f)
{
// if this key is in our new binding list, it's a "release", and we're done
addNewBinding();
stopListeningForInput();
return;
}
// otherwise, keep waiting
return;
}
}
// new binding, add it to the list, but wait for a decent distance first, and then wait for release
if (value >= 0.25f)
m_new_bindings.push_back(key);
}
void InputBindingDialog::hookInputManager()
{
InputManager::SetHook([this](InputBindingKey key, float value) {
QMetaObject::invokeMethod(this, "inputManagerHookCallback", Qt::QueuedConnection, Q_ARG(InputBindingKey, key),
Q_ARG(float, value));
return InputInterceptHook::CallbackResult::StopProcessingEvent;
});
}
void InputBindingDialog::unhookInputManager()
{
InputManager::RemoveHook();
}

View File

@ -0,0 +1,68 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ui_InputBindingDialog.h"
#include "Frontend/InputManager.h"
#include <QtWidgets/QDialog>
#include <optional>
#include <string>
#include <vector>
class InputBindingDialog : public QDialog
{
Q_OBJECT
public:
InputBindingDialog(std::string section_name, std::string key_name, std::vector<std::string> bindings, QWidget* parent);
~InputBindingDialog();
protected Q_SLOTS:
void onAddBindingButtonClicked();
void onRemoveBindingButtonClicked();
void onClearBindingsButtonClicked();
void onInputListenTimerTimeout();
void inputManagerHookCallback(InputBindingKey key, float value);
protected:
enum : u32
{
TIMEOUT_FOR_BINDING = 5
};
virtual bool eventFilter(QObject* watched, QEvent* event) override;
virtual void startListeningForInput(u32 timeout_in_seconds);
virtual void stopListeningForInput();
bool isListeningForInput() const { return m_input_listen_timer != nullptr; }
void addNewBinding();
void updateList();
void saveListToSettings();
void hookInputManager();
void unhookInputManager();
Ui::InputBindingDialog m_ui;
std::string m_section_name;
std::string m_key_name;
std::vector<std::string> m_bindings;
std::vector<InputBindingKey> m_new_bindings;
QTimer* m_input_listen_timer = nullptr;
u32 m_input_listen_remaining_seconds = 0;
};

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>InputBindingDialog</class>
<widget class="QDialog" name="InputBindingDialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>533</width>
<height>283</height>
</rect>
</property>
<property name="windowTitle">
<string>Edit Bindings</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="title">
<property name="text">
<string>Bindings for Controller0/ButtonCircle</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="bindingList"/>
</item>
<item>
<widget class="QLabel" name="status">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="addBinding">
<property name="text">
<string>Add Binding</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeBinding">
<property name="text">
<string>Remove Binding</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearBindings">
<property name="text">
<string>Clear Bindings</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,371 @@
/* PCSX2 - PS2 Emulator for PCs
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "EmuThread.h"
#include "QtHost.h"
#include "QtUtils.h"
#include "Settings/ControllerSettingsDialog.h"
#include "Settings/InputBindingDialog.h"
#include "Settings/InputBindingWidget.h"
#include <QtCore/QTimer>
#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
#include <QtWidgets/QInputDialog>
#include <cmath>
#include <sstream>
#include "pcsx2/GS/GSIntrin.h" // _BitScanForward
InputBindingWidget::InputBindingWidget(QWidget* parent)
: QPushButton(parent)
{
connect(this, &QPushButton::clicked, this, &InputBindingWidget::onClicked);
}
InputBindingWidget::InputBindingWidget(QWidget* parent, std::string section_name, std::string key_name)
: QPushButton(parent)
{
setMinimumWidth(225);
setMaximumWidth(225);
connect(this, &QPushButton::clicked, this, &InputBindingWidget::onClicked);
setKey(std::move(section_name), std::move(key_name));
}
InputBindingWidget::~InputBindingWidget()
{
Q_ASSERT(!isListeningForInput());
}
void InputBindingWidget::setKey(std::string section_name, std::string key_name)
{
m_section_name = std::move(section_name);
m_key_name = std::move(key_name);
m_bindings = QtHost::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
updateText();
}
void InputBindingWidget::updateText()
{
if (m_bindings.empty())
{
setText(QString());
}
else if (m_bindings.size() > 1)
{
setText(tr("%n bindings", "", static_cast<int>(m_bindings.size())));
// keep the full thing for the tooltip
std::stringstream ss;
bool first = true;
for (const std::string& binding : m_bindings)
{
if (first)
first = false;
else
ss << "\n";
ss << binding;
}
setToolTip(QString::fromStdString(ss.str()));
}
else
{
QString binding_text(QString::fromStdString(m_bindings[0]));
setToolTip(binding_text);
// fix up accelerators, and if it's too long, ellipsise it
if (binding_text.contains('&'))
binding_text = binding_text.replace(QStringLiteral("&"), QStringLiteral("&&"));
if (binding_text.length() > 35)
binding_text = binding_text.left(35).append(QStringLiteral("..."));
setText(binding_text);
}
}
bool InputBindingWidget::eventFilter(QObject* watched, QEvent* event)
{
const QEvent::Type event_type = event->type();
// if the key is being released, set the input
if (event_type == QEvent::KeyRelease || event_type == QEvent::MouseButtonPress)
{
setNewBinding();
stopListeningForInput();
return true;
}
else if (event_type == QEvent::KeyPress)
{
const QKeyEvent* key_event = static_cast<const QKeyEvent*>(event);
m_new_bindings.push_back(InputManager::MakeHostKeyboardKey(key_event->key()));
return true;
}
else if (event_type == QEvent::MouseButtonPress)
{
unsigned long button_index;
if (_BitScanForward(&button_index, static_cast<u32>(static_cast<const QMouseEvent*>(event)->button())))
m_new_bindings.push_back(InputManager::MakeHostMouseButtonKey(button_index));
return true;
}
else if (event_type == QEvent::MouseButtonDblClick)
{
// just eat double clicks
return true;
}
return false;
}
bool InputBindingWidget::event(QEvent* event)
{
if (event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent* mev = static_cast<QMouseEvent*>(event);
if (mev->button() == Qt::LeftButton && mev->modifiers() & Qt::ShiftModifier)
{
openDialog();
return false;
}
}
return QPushButton::event(event);
}
void InputBindingWidget::mouseReleaseEvent(QMouseEvent* e)
{
if (e->button() == Qt::RightButton)
{
clearBinding();
return;
}
QPushButton::mouseReleaseEvent(e);
}
void InputBindingWidget::setNewBinding()
{
if (m_new_bindings.empty())
return;
const std::string new_binding(
InputManager::ConvertInputBindingKeysToString(m_new_bindings.data(), m_new_bindings.size()));
if (!new_binding.empty())
{
QtHost::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), new_binding.c_str());
g_emu_thread->reloadInputBindings();
}
m_bindings.clear();
m_bindings.push_back(std::move(new_binding));
}
void InputBindingWidget::clearBinding()
{
m_bindings.clear();
QtHost::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
g_emu_thread->reloadInputBindings();
updateText();
}
void InputBindingWidget::reloadBinding()
{
m_bindings = QtHost::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
updateText();
}
void InputBindingWidget::onClicked()
{
if (m_bindings.size() > 1)
{
openDialog();
return;
}
if (isListeningForInput())
stopListeningForInput();
startListeningForInput(TIMEOUT_FOR_SINGLE_BINDING);
}
void InputBindingWidget::onInputListenTimerTimeout()
{
m_input_listen_remaining_seconds--;
if (m_input_listen_remaining_seconds == 0)
{
stopListeningForInput();
return;
}
setText(tr("Push Button/Axis... [%1]").arg(m_input_listen_remaining_seconds));
}
void InputBindingWidget::startListeningForInput(u32 timeout_in_seconds)
{
m_new_bindings.clear();
m_input_listen_timer = new QTimer(this);
m_input_listen_timer->setSingleShot(false);
m_input_listen_timer->start(1000);
m_input_listen_timer->connect(m_input_listen_timer, &QTimer::timeout, this,
&InputBindingWidget::onInputListenTimerTimeout);
m_input_listen_remaining_seconds = timeout_in_seconds;
setText(tr("Push Button/Axis... [%1]").arg(m_input_listen_remaining_seconds));
installEventFilter(this);
grabKeyboard();
grabMouse();
hookInputManager();
}
void InputBindingWidget::stopListeningForInput()
{
updateText();
delete m_input_listen_timer;
m_input_listen_timer = nullptr;
std::vector<InputBindingKey>().swap(m_new_bindings);
unhookInputManager();
releaseMouse();
releaseKeyboard();
removeEventFilter(this);
}
void InputBindingWidget::inputManagerHookCallback(InputBindingKey key, float value)
{
const float abs_value = std::abs(value);
for (InputBindingKey other_key : m_new_bindings)
{
if (other_key.MaskDirection() == key.MaskDirection())
{
if (abs_value < 0.5f)
{
// if this key is in our new binding list, it's a "release", and we're done
setNewBinding();
stopListeningForInput();
return;
}
// otherwise, keep waiting
return;
}
}
// new binding, add it to the list, but wait for a decent distance first, and then wait for release
if (abs_value >= 0.5f)
{
InputBindingKey key_to_add = key;
key_to_add.negative = (value < 0.0f);
m_new_bindings.push_back(key_to_add);
}
}
void InputBindingWidget::hookInputManager()
{
InputManager::SetHook([this](InputBindingKey key, float value) {
QMetaObject::invokeMethod(this, "inputManagerHookCallback", Qt::QueuedConnection, Q_ARG(InputBindingKey, key),
Q_ARG(float, value));
return InputInterceptHook::CallbackResult::StopProcessingEvent;
});
}
void InputBindingWidget::unhookInputManager()
{
InputManager::RemoveHook();
}
void InputBindingWidget::openDialog()
{
InputBindingDialog binding_dialog(m_section_name, m_key_name, m_bindings, QtUtils::GetRootWidget(this));
binding_dialog.exec();
reloadBinding();
}
InputVibrationBindingWidget::InputVibrationBindingWidget(QWidget* parent)
{
connect(this, &QPushButton::clicked, this, &InputVibrationBindingWidget::onClicked);
}
InputVibrationBindingWidget::InputVibrationBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, std::string section_name, std::string key_name)
{
setMinimumWidth(225);
setMaximumWidth(225);
connect(this, &QPushButton::clicked, this, &InputVibrationBindingWidget::onClicked);
setKey(dialog, std::move(section_name), std::move(key_name));
}
InputVibrationBindingWidget::~InputVibrationBindingWidget()
{
}
void InputVibrationBindingWidget::setKey(ControllerSettingsDialog* dialog, std::string section_name, std::string key_name)
{
m_dialog = dialog;
m_section_name = std::move(section_name);
m_key_name = std::move(key_name);
m_binding = QtHost::GetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str());
setText(QString::fromStdString(m_binding));
}
void InputVibrationBindingWidget::clearBinding()
{
m_binding = {};
QtHost::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
g_emu_thread->reloadInputBindings();
setText(QString());
}
void InputVibrationBindingWidget::onClicked()
{
QInputDialog dialog(QtUtils::GetRootWidget(this));
const QString full_key(QStringLiteral("%1/%2").arg(QString::fromStdString(m_section_name)).arg(QString::fromStdString(m_key_name)));
const QString current(QString::fromStdString(m_binding));
QStringList input_options(m_dialog->getVibrationMotors());
if (!current.isEmpty() && input_options.indexOf(current) < 0)
input_options.append(current);
QInputDialog input_dialog(this);
input_dialog.setWindowTitle(full_key);
input_dialog.setLabelText(tr("Select vibration motor for %1.").arg(full_key));
input_dialog.setInputMode(QInputDialog::TextInput);
input_dialog.setOptions(QInputDialog::UseListViewForComboBoxItems);
input_dialog.setComboBoxEditable(false);
input_dialog.setComboBoxItems(std::move(input_options));
input_dialog.setTextValue(current);
if (input_dialog.exec() == 0)
return;
const QString new_value(input_dialog.textValue());
m_binding = new_value.toStdString();
QtHost::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_binding.c_str());
setText(new_value);
}
void InputVibrationBindingWidget::mouseReleaseEvent(QMouseEvent* e)
{
if (e->button() == Qt::RightButton)
{
clearBinding();
return;
}
QPushButton::mouseReleaseEvent(e);
}

View File

@ -0,0 +1,102 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "pcsx2/Frontend/InputManager.h"
#include <QtWidgets/QPushButton>
#include <optional>
class QTimer;
class ControllerSettingsDialog;
class InputBindingWidget : public QPushButton
{
Q_OBJECT
public:
InputBindingWidget(QWidget* parent);
InputBindingWidget(QWidget* parent, std::string section_name, std::string key_name);
~InputBindingWidget();
void setKey(std::string section_name, std::string key_name);
public Q_SLOTS:
void clearBinding();
void reloadBinding();
protected Q_SLOTS:
void onClicked();
void onInputListenTimerTimeout();
void inputManagerHookCallback(InputBindingKey key, float value);
protected:
enum : u32
{
TIMEOUT_FOR_SINGLE_BINDING = 5,
TIMEOUT_FOR_ALL_BINDING = 10
};
virtual bool eventFilter(QObject* watched, QEvent* event) override;
virtual bool event(QEvent* event) override;
virtual void mouseReleaseEvent(QMouseEvent* e) override;
virtual void startListeningForInput(u32 timeout_in_seconds);
virtual void stopListeningForInput();
virtual void openDialog();
bool isListeningForInput() const { return m_input_listen_timer != nullptr; }
void setNewBinding();
void updateText();
void hookInputManager();
void unhookInputManager();
std::string m_section_name;
std::string m_key_name;
std::vector<std::string> m_bindings;
std::vector<InputBindingKey> m_new_bindings;
QTimer* m_input_listen_timer = nullptr;
u32 m_input_listen_remaining_seconds = 0;
};
class InputVibrationBindingWidget : public QPushButton
{
Q_OBJECT
public:
InputVibrationBindingWidget(QWidget* parent);
InputVibrationBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, std::string section_name, std::string key_name);
~InputVibrationBindingWidget();
void setKey(ControllerSettingsDialog* dialog, std::string section_name, std::string key_name);
public Q_SLOTS:
void clearBinding();
protected Q_SLOTS:
void onClicked();
protected:
virtual void mouseReleaseEvent(QMouseEvent* e) override;
private:
std::string m_section_name;
std::string m_key_name;
std::string m_binding;
ControllerSettingsDialog* m_dialog;
};

View File

@ -0,0 +1,101 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "InterfaceSettingsWidget.h"
#include "MainWindow.h"
#include "SettingWidgetBinder.h"
#include "SettingsDialog.h"
static const char* THEME_NAMES[] = {QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Native"),
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Fusion"),
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Dark Fusion (Gray)"),
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Dark Fusion (Blue)"), nullptr};
static const char* THEME_VALUES[] = {"", "fusion", "darkfusion", "darkfusionblue", nullptr};
InterfaceSettingsWidget::InterfaceSettingsWidget(QWidget* parent, SettingsDialog* dialog)
: QWidget(parent)
{
m_ui.setupUi(this);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.inhibitScreensaver, "UI", "InhibitScreensaver", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.discordPresence, "UI", "DiscordPresence", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.confirmPowerOff, "UI", "ConfirmPowerOff", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.saveStateOnExit, "EmuCore", "AutoStateLoadSave", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.pauseOnStart, "UI", "StartPaused", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.pauseOnFocusLoss, "UI", "PauseOnFocusLoss", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.startFullscreen, "UI", "StartFullscreen", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.doubleClickTogglesFullscreen, "UI", "DoubleClickTogglesFullscreen",
true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.hideMouseCursor, "UI", "HideMouseCursor", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.renderToMainWindow, "UI", "RenderToMainWindow", true);
SettingWidgetBinder::BindWidgetToEnumSetting(m_ui.theme, "UI", "Theme", THEME_NAMES, THEME_VALUES,
MainWindow::DEFAULT_THEME_NAME);
connect(m_ui.theme, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() { emit themeChanged(); });
dialog->registerWidgetHelp(
m_ui.inhibitScreensaver, tr("Inhibit Screensaver"), tr("Checked"),
tr("Prevents the screen saver from activating and the host from sleeping while emulation is running."));
dialog->registerWidgetHelp(m_ui.discordPresence, tr("Enable Discord Presence"), tr("Unchecked"),
tr("Shows the game you are currently playing as part of your profile in Discord."));
if (true)
{
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.autoUpdateEnabled, "AutoUpdater", "CheckAtStartup", true);
dialog->registerWidgetHelp(m_ui.autoUpdateEnabled, tr("Enable Automatic Update Check"), tr("Checked"),
tr("Automatically checks for updates to the program on startup. Updates can be deferred "
"until later or skipped entirely."));
// m_ui.autoUpdateTag->addItems(AutoUpdaterDialog::getTagList());
// SettingWidgetBinder::BindWidgetToStringSetting(m_ui.autoUpdateTag, "AutoUpdater", "UpdateTag",
// AutoUpdaterDialog::getDefaultTag());
// m_ui.autoUpdateCurrentVersion->setText(tr("%1 (%2)").arg(g_scm_tag_str).arg(g_scm_date_str));
// connect(m_ui.checkForUpdates, &QPushButton::clicked, [this]() {
// m_host_interface->getMainWindow()->checkForUpdates(true); });
}
else
{
m_ui.verticalLayout->removeWidget(m_ui.automaticUpdaterGroup);
m_ui.automaticUpdaterGroup->hide();
}
dialog->registerWidgetHelp(
m_ui.confirmPowerOff, tr("Confirm Power Off"), tr("Checked"),
tr("Determines whether a prompt will be displayed to confirm shutting down the emulator/game "
"when the hotkey is pressed."));
dialog->registerWidgetHelp(m_ui.saveStateOnExit, tr("Save State On Exit"), tr("Checked"),
tr("Automatically saves the emulator state when powering down or exiting. You can then "
"resume directly from where you left off next time."));
dialog->registerWidgetHelp(m_ui.pauseOnStart, tr("Pause On Start"), tr("Unchecked"),
tr("Pauses the emulator when a game is started."));
dialog->registerWidgetHelp(m_ui.pauseOnFocusLoss, tr("Pause On Focus Loss"), tr("Unchecked"),
tr("Pauses the emulator when you minimize the window or switch to another application, "
"and unpauses when you switch back."));
dialog->registerWidgetHelp(m_ui.startFullscreen, tr("Start Fullscreen"), tr("Unchecked"),
tr("Automatically switches to fullscreen mode when a game is started."));
dialog->registerWidgetHelp(m_ui.hideMouseCursor, tr("Hide Cursor In Fullscreen"), tr("Checked"),
tr("Hides the mouse pointer/cursor when the emulator is in fullscreen mode."));
dialog->registerWidgetHelp(
m_ui.renderToMainWindow, tr("Render To Main Window"), tr("Checked"),
tr("Renders the display of the simulated console to the main window of the application, over "
"the game list. If unchecked, the display will render in a separate window."));
}
InterfaceSettingsWidget::~InterfaceSettingsWidget() = default;

View File

@ -0,0 +1,37 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtWidgets/QWidget>
#include "ui_InterfaceSettingsWidget.h"
class SettingsDialog;
class InterfaceSettingsWidget : public QWidget
{
Q_OBJECT
public:
InterfaceSettingsWidget(QWidget* parent, SettingsDialog* dialog);
~InterfaceSettingsWidget();
Q_SIGNALS:
void themeChanged();
private:
Ui::InterfaceSettingsWidget m_ui;
};

View File

@ -0,0 +1,240 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>InterfaceSettingsWidget</class>
<widget class="QWidget" name="InterfaceSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>698</width>
<height>740</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Behaviour</string>
</property>
<layout class="QGridLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="inhibitScreensaver">
<property name="text">
<string>Inhibit Screensaver</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="discordPresence">
<property name="text">
<string>Enable Discord Presence</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="pauseOnStart">
<property name="text">
<string>Pause On Start</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="pauseOnFocusLoss">
<property name="text">
<string>Pause On Focus Loss</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="confirmPowerOff">
<property name="text">
<string>Confirm Power Off</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="saveStateOnExit">
<property name="text">
<string>Save/Load State On Exit/Resume</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Game Display</string>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QCheckBox" name="startFullscreen">
<property name="text">
<string>Start Fullscreen</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="hideMouseCursor">
<property name="text">
<string>Hide Mouse Cursor</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="renderToMainWindow">
<property name="text">
<string>Render To Main Window</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="doubleClickTogglesFullscreen">
<property name="text">
<string>Double-Click Toggles Fullscreen</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="disableWindowResizing">
<property name="text">
<string>Disable Window Resizing</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Preferences</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Language:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="language"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Theme:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="theme"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="automaticUpdaterGroup">
<property name="title">
<string>Automatic Updater</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Update Channel:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="autoUpdateTag"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Current Version:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="autoUpdateCurrentVersion">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="autoUpdateEnabled">
<property name="text">
<string>Enable Automatic Update Check</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="checkForUpdates">
<property name="text">
<string>Check for Updates...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OSDSettingsWidget</class>
<widget class="QWidget" name="OSDSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>604</width>
<height>469</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
<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>
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>On-Screen Display</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>OSD Scale:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="osdScale">
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>100</number>
</property>
<property name="maximum">
<number>500</number>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="osdShowMessages">
<property name="text">
<string>Show Notifications</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="osdShowSpeed">
<property name="text">
<string>Show Speed</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="osdShowFPS">
<property name="text">
<string>Show FPS</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="osdShowResolution">
<property name="text">
<string>Show Resolution</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="osdShowCPU">
<property name="text">
<string>Show CPU Usage</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="osdShowGSStats">
<property name="text">
<string>Show Statistics</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,156 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "QtHost.h"
#include "SettingsDialog.h"
#include "AdvancedSystemSettingsWidget.h"
#include "BIOSSettingsWidget.h"
#include "EmulationSettingsWidget.h"
#include "GameFixSettingsWidget.h"
#include "GameListSettingsWidget.h"
#include "GraphicsSettingsWidget.h"
#include "HotkeySettingsWidget.h"
#include "InterfaceSettingsWidget.h"
#include "SystemSettingsWidget.h"
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QTextEdit>
static constexpr char DEFAULT_SETTING_HELP_TEXT[] = "";
SettingsDialog::SettingsDialog(QWidget* parent /* = nullptr */)
: QDialog(parent)
{
m_ui.setupUi(this);
setCategoryHelpTexts();
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_interface_settings = new InterfaceSettingsWidget(m_ui.settingsContainer, this);
m_game_list_settings = new GameListSettingsWidget(m_ui.settingsContainer, this);
m_bios_settings = new BIOSSettingsWidget(m_ui.settingsContainer, this);
m_emulation_settings = new EmulationSettingsWidget(m_ui.settingsContainer, this);
m_system_settings = new SystemSettingsWidget(m_ui.settingsContainer, this);
m_advanced_system_settings = new AdvancedSystemSettingsWidget(m_ui.settingsContainer, this);
m_game_fix_settings_widget = new GameFixSettingsWidget(m_ui.settingsContainer, this);
m_graphics_settings = new GraphicsSettingsWidget(m_ui.settingsContainer, this);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::InterfaceSettings), m_interface_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::GameListSettings), m_game_list_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::BIOSSettings), m_bios_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::EmulationSettings), m_emulation_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::SystemSettings), m_system_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::AdvancedSystemSettings), m_advanced_system_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::GameFixSettings), m_game_fix_settings_widget);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::GraphicsSettings), m_graphics_settings);
m_ui.settingsCategory->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
m_ui.settingsCategory->setCurrentRow(0);
m_ui.settingsContainer->setCurrentIndex(0);
m_ui.helpText->setText(m_category_help_text[0]);
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, &SettingsDialog::onCategoryCurrentRowChanged);
connect(m_ui.closeButton, &QPushButton::clicked, this, &SettingsDialog::accept);
connect(m_ui.restoreDefaultsButton, &QPushButton::clicked, this, &SettingsDialog::onRestoreDefaultsClicked);
}
SettingsDialog::~SettingsDialog() = default;
void SettingsDialog::setCategoryHelpTexts()
{
m_category_help_text[static_cast<int>(Category::InterfaceSettings)] =
tr("<strong>Interface Settings</strong><hr>These options control how the software looks and behaves.<br><br>Mouse "
"over "
"an option for additional information.");
m_category_help_text[static_cast<int>(Category::SystemSettings)] =
tr("<strong>System Settings</strong><hr>These options determine the configuration of the simulated "
"console.<br><br>Mouse over an option for additional information.");
m_category_help_text[static_cast<int>(Category::GameListSettings)] =
tr("<strong>Game List Settings</strong><hr>The list above shows the directories which will be searched by "
"PCSX2 to populate the game list. Search directories can be added, removed, and switched to "
"recursive/non-recursive.");
m_category_help_text[static_cast<int>(Category::AudioSettings)] =
tr("<strong>Audio Settings</strong><hr>These options control the audio output of the console. Mouse over an option "
"for additional information.");
}
void SettingsDialog::setCategory(Category category)
{
if (category >= Category::Count)
return;
m_ui.settingsCategory->setCurrentRow(static_cast<int>(category));
}
void SettingsDialog::onCategoryCurrentRowChanged(int row)
{
Q_ASSERT(row < static_cast<int>(Category::Count));
m_ui.settingsContainer->setCurrentIndex(row);
m_ui.helpText->setText(m_category_help_text[row]);
}
void SettingsDialog::onRestoreDefaultsClicked()
{
if (QMessageBox::question(this, tr("Confirm Restore Defaults"),
tr("Are you sure you want to restore the default settings? Any preferences will be lost."),
QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes)
{
return;
}
// TODO
}
void SettingsDialog::registerWidgetHelp(QObject* object, QString title, QString recommended_value, QString text)
{
// construct rich text with formatted description
QString full_text;
full_text += "<table width='100%' cellpadding='0' cellspacing='0'><tr><td><strong>";
full_text += title;
full_text += "</strong></td><td align='right'><strong>";
full_text += tr("Recommended Value");
full_text += ": </strong>";
full_text += recommended_value;
full_text += "</td></table><hr>";
full_text += text;
m_widget_help_text_map[object] = std::move(full_text);
object->installEventFilter(this);
}
bool SettingsDialog::eventFilter(QObject* object, QEvent* event)
{
if (event->type() == QEvent::Enter)
{
auto iter = m_widget_help_text_map.constFind(object);
if (iter != m_widget_help_text_map.end())
{
m_current_help_widget = object;
m_ui.helpText->setText(iter.value());
}
}
else if (event->type() == QEvent::Leave)
{
if (m_current_help_widget)
{
m_current_help_widget = nullptr;
m_ui.helpText->setText(m_category_help_text[m_ui.settingsCategory->currentRow()]);
}
}
return QDialog::eventFilter(object, event);
}

View File

@ -0,0 +1,101 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ui_SettingsDialog.h"
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtWidgets/QDialog>
#include <array>
class InterfaceSettingsWidget;
class GameListSettingsWidget;
class EmulationSettingsWidget;
class BIOSSettingsWidget;
class SystemSettingsWidget;
class AdvancedSystemSettingsWidget;
class GameFixSettingsWidget;
class GraphicsSettingsWidget;
class AudioSettingsWidget;
class MemoryCardSettingsWidget;
class SettingsDialog final : public QDialog
{
Q_OBJECT
public:
enum class Category
{
InterfaceSettings,
GameListSettings,
BIOSSettings,
EmulationSettings,
SystemSettings,
AdvancedSystemSettings,
GameFixSettings,
GraphicsSettings,
AudioSettings,
MemoryCardSettings,
Count
};
explicit SettingsDialog(QWidget* parent = nullptr);
~SettingsDialog();
InterfaceSettingsWidget* getInterfaceSettingsWidget() const { return m_interface_settings; }
GameListSettingsWidget* getGameListSettingsWidget() const { return m_game_list_settings; }
BIOSSettingsWidget* getBIOSSettingsWidget() const { return m_bios_settings; }
EmulationSettingsWidget* getEmulationSettingsWidget() const { return m_emulation_settings; }
SystemSettingsWidget* getSystemSettingsWidget() const { return m_system_settings; }
AdvancedSystemSettingsWidget* getAdvancedSystemSettingsWidget() const { return m_advanced_system_settings; }
GameFixSettingsWidget* getGameFixSettingsWidget() const { return m_game_fix_settings_widget; }
GraphicsSettingsWidget* getGraphicsSettingsWidget() const { return m_graphics_settings; }
AudioSettingsWidget* getAudioSettingsWidget() const { return m_audio_settings; }
MemoryCardSettingsWidget* getMemoryCardSettingsWidget() const { return m_memory_card_settings; }
void registerWidgetHelp(QObject* object, QString title, QString recommended_value, QString text);
bool eventFilter(QObject* object, QEvent* event) override;
Q_SIGNALS:
void settingsResetToDefaults();
public Q_SLOTS:
void setCategory(Category category);
private Q_SLOTS:
void onCategoryCurrentRowChanged(int row);
void onRestoreDefaultsClicked();
private:
void setCategoryHelpTexts();
Ui::SettingsDialog m_ui;
InterfaceSettingsWidget* m_interface_settings = nullptr;
GameListSettingsWidget* m_game_list_settings = nullptr;
BIOSSettingsWidget* m_bios_settings = nullptr;
EmulationSettingsWidget* m_emulation_settings = nullptr;
SystemSettingsWidget* m_system_settings = nullptr;
AdvancedSystemSettingsWidget* m_advanced_system_settings = nullptr;
GameFixSettingsWidget* m_game_fix_settings_widget = nullptr;
GraphicsSettingsWidget* m_graphics_settings = nullptr;
AudioSettingsWidget* m_audio_settings = nullptr;
MemoryCardSettingsWidget* m_memory_card_settings = nullptr;
std::array<QString, static_cast<int>(Category::Count)> m_category_help_text;
QObject* m_current_help_widget = nullptr;
QMap<QObject*, QString> m_widget_help_text_map;
};

View File

@ -0,0 +1,227 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsDialog</class>
<widget class="QDialog" name="SettingsDialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>780</width>
<height>650</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>PCSX2 Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
<item row="0" column="0">
<widget class="QListWidget" name="settingsCategory">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<item>
<property name="text">
<string>Interface</string>
</property>
<property name="icon">
<iconset theme="settings-3-line"/>
</property>
</item>
<item>
<property name="text">
<string>Game List</string>
</property>
<property name="icon">
<iconset theme="folder-settings-line"/>
</property>
</item>
<item>
<property name="text">
<string>BIOS</string>
</property>
<property name="icon">
<iconset theme="hard-drive-2-line"/>
</property>
</item>
<item>
<property name="text">
<string>Emulation</string>
</property>
<property name="icon">
<iconset theme="dashboard-line"/>
</property>
</item>
<item>
<property name="text">
<string>System</string>
</property>
<property name="icon">
<iconset theme="artboard-2-line"/>
</property>
</item>
<item>
<property name="text">
<string>Advanced System</string>
</property>
<property name="icon">
<iconset theme="artboard-2-line"/>
</property>
</item>
<item>
<property name="text">
<string>Game Fixes</string>
</property>
<property name="icon">
<iconset theme="close-line"/>
</property>
</item>
<item>
<property name="text">
<string>Graphics</string>
</property>
<property name="icon">
<iconset theme="brush-line"/>
</property>
</item>
<item>
<property name="text">
<string>Audio</string>
</property>
<property name="icon">
<iconset theme="volume-up-line"/>
</property>
</item>
<item>
<property name="text">
<string>Memory Cards</string>
</property>
<property name="icon">
<iconset theme="sd-card-line"/>
</property>
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QStackedWidget" name="settingsContainer">
<property name="minimumSize">
<size>
<width>500</width>
<height>0</height>
</size>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page"/>
<widget class="QWidget" name="page_2"/>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTextEdit" name="helpText">
<property name="minimumSize">
<size>
<width>0</width>
<height>120</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>120</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QComboBox" name="settingsPreset">
<item>
<property name="text">
<string>Preset: Custom</string>
</property>
</item>
<item>
<property name="text">
<string>Preset: Safe (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Preset: Fast</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QPushButton" name="restoreDefaultsButton">
<property name="text">
<string>Restore Defaults</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="text">
<string>Close</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,88 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include <QtWidgets/QMessageBox>
#include <algorithm>
#include "EmuThread.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#include "SettingsDialog.h"
#include "SystemSettingsWidget.h"
static constexpr int MINIMUM_EE_CYCLE_RATE = -3;
static constexpr int MAXIMUM_EE_CYCLE_RATE = 3;
static constexpr int DEFAULT_EE_CYCLE_RATE = 0;
static constexpr int DEFAULT_EE_CYCLE_SKIP = 0;
SystemSettingsWidget::SystemSettingsWidget(QWidget* parent, SettingsDialog* dialog)
: QWidget(parent)
{
m_ui.setupUi(this);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.eeRoundingMode, "EmuCore/CPU", "FPU.Roundmode", 3);
m_ui.eeClampMode->setCurrentIndex(getClampingModeIndex(false));
connect(m_ui.eeClampMode, QOverload<int>::of(&QComboBox::currentIndexChanged),
[this](int index) { setClampingMode(false, index); });
m_ui.eeCycleRate->setCurrentIndex(
std::clamp(QtHost::GetBaseIntSettingValue("EmuCore/Speedhacks", "EECycleRate", DEFAULT_EE_CYCLE_RATE),
MINIMUM_EE_CYCLE_RATE, MAXIMUM_EE_CYCLE_RATE) +
(0 - MINIMUM_EE_CYCLE_RATE));
connect(m_ui.eeCycleRate, QOverload<int>::of(&QComboBox::currentIndexChanged), [](int index) {
QtHost::SetBaseIntSettingValue("EmuCore/Speedhacks", "EECycleRate", MINIMUM_EE_CYCLE_RATE + index);
g_emu_thread->applySettings();
});
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.eeCycleSkipping, "EmuCore/Speedhacks", "EECycleSkip", 0);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.MTVU, "EmuCore/Speedhacks", "vuThread", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.instantVU1, "EmuCore/Speedhacks", "vu1Instant", true);
SettingWidgetBinder::BindWidgetToIntSetting(m_ui.vuRoundingMode, "EmuCore/CPU", "VU.Roundmode", 3);
m_ui.vuClampMode->setCurrentIndex(getClampingModeIndex(true));
connect(m_ui.vuClampMode, QOverload<int>::of(&QComboBox::currentIndexChanged),
[this](int index) { setClampingMode(true, index); });
SettingWidgetBinder::BindWidgetToBoolSetting(m_ui.fastCDVD, "EmuCore/Speedhacks", "fastCDVD", false);
updateVU1InstantState();
connect(m_ui.MTVU, &QCheckBox::stateChanged, this, &SystemSettingsWidget::updateVU1InstantState);
}
SystemSettingsWidget::~SystemSettingsWidget() = default;
void SystemSettingsWidget::updateVU1InstantState()
{
m_ui.instantVU1->setEnabled(!m_ui.MTVU->isChecked());
}
int SystemSettingsWidget::getClampingModeIndex(bool vu)
{
if (QtHost::GetBaseBoolSettingValue("EmuCore/CPU/Recompiler", vu ? "vuSignOverflow" : "fpuFullMode", false))
return 3;
if (QtHost::GetBaseBoolSettingValue("EmuCore/CPU/Recompiler", vu ? "vuExtraOverflow" : "fpuExtraOverflow", false))
return 2;
if (QtHost::GetBaseBoolSettingValue("EmuCore/CPU/Recompiler", vu ? "vuOverflow" : "fpuOverflow", true))
return 1;
return 0;
}
void SystemSettingsWidget::setClampingMode(bool vu, int index)
{
QtHost::SetBaseBoolSettingValue("EmuCore/CPU/Recompiler", vu ? "vuSignOverflow" : "fpuFullMode", (index >= 3));
QtHost::SetBaseBoolSettingValue("EmuCore/CPU/Recompiler", vu ? "vuExtraOverflow" : "fpuExtraOverflow", (index >= 2));
QtHost::SetBaseBoolSettingValue("EmuCore/CPU/Recompiler", vu ? "vuOverflow" : "fpuOverflow", (index >= 1));
g_emu_thread->applySettings();
}

View File

@ -0,0 +1,40 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtWidgets/QWidget>
#include "ui_SystemSettingsWidget.h"
class SettingsDialog;
class SystemSettingsWidget : public QWidget
{
Q_OBJECT
public:
SystemSettingsWidget(QWidget* parent, SettingsDialog* dialog);
~SystemSettingsWidget();
private Q_SLOTS:
void updateVU1InstantState();
private:
static int getClampingModeIndex(bool vu);
static void setClampingMode(bool vu, int index);
Ui::SystemSettingsWidget m_ui;
};

View File

@ -0,0 +1,301 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SystemSettingsWidget</class>
<widget class="QWidget" name="SystemSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>648</width>
<height>454</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,1">
<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>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>EmotionEngine (EE, MIPS-IV)</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Cycle Rate:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="eeCycleRate">
<item>
<property name="text">
<string>50% Speed</string>
</property>
</item>
<item>
<property name="text">
<string>60% Speed</string>
</property>
</item>
<item>
<property name="text">
<string>75% Speed</string>
</property>
</item>
<item>
<property name="text">
<string>100% (Normal Speed)</string>
</property>
</item>
<item>
<property name="text">
<string>130% Speed</string>
</property>
</item>
<item>
<property name="text">
<string>180% Speed</string>
</property>
</item>
<item>
<property name="text">
<string>300% Speed</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Cycle Skip:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="eeCycleSkipping">
<item>
<property name="text">
<string>Normal</string>
</property>
</item>
<item>
<property name="text">
<string>Mild Underclock</string>
</property>
</item>
<item>
<property name="text">
<string>Moderate Underclock</string>
</property>
</item>
<item>
<property name="text">
<string>Maximum Underclock</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Rounding Mode:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="eeRoundingMode">
<item>
<property name="text">
<string>Nearest</string>
</property>
</item>
<item>
<property name="text">
<string>Negative</string>
</property>
</item>
<item>
<property name="text">
<string>Positive</string>
</property>
</item>
<item>
<property name="text">
<string>Chop/Zero (Default)</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Clamping Mode:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="eeClampMode">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Normal (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Extra + Preserve Sign</string>
</property>
</item>
<item>
<property name="text">
<string>Full</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Vector Units (VU)</string>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Rounding Mode:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="vuRoundingMode">
<item>
<property name="text">
<string>Nearest</string>
</property>
</item>
<item>
<property name="text">
<string>Negative</string>
</property>
</item>
<item>
<property name="text">
<string>Positive</string>
</property>
</item>
<item>
<property name="text">
<string>Chop/Zero (Default)</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Clamping Mode:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="vuClampMode">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Normal (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Extra + Preserve Sign</string>
</property>
</item>
<item>
<property name="text">
<string>Full</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="MTVU">
<property name="text">
<string>MTVU (Multi-Threaded VU1)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="instantVU1">
<property name="text">
<string>Instant VU1</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>I/O Processor (IOP, MIPS-I)</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QCheckBox" name="fastCDVD">
<property name="text">
<string>Enable Fast CDVD</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

292
pcsx2-qt/pcsx2-qt.vcxproj Normal file
View File

@ -0,0 +1,292 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
<Import Project="$(SolutionDir)common\vsprops\ProjectConfigAVX2.props" />
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{2A016F21-87AE-4154-8271-1F57E91408E9}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="$(SolutionDir)common\vsprops\common.props" />
<Import Project="$(SolutionDir)common\vsprops\BaseProperties.props" />
<Import Project="$(SolutionDir)common\vsprops\3rdpartyDeps.props" />
<Import Project="$(SolutionDir)common\vsprops\pthreads.props" />
<Import Project="$(SolutionDir)common\vsprops\QtCompile.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="$(SolutionDir)common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="$(SolutionDir)common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="$(SolutionDir)common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="$(SolutionDir)common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<TargetName>$(EXEString)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\xbyak;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\freetype\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\xz\xz\src\liblzma\api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\baseclasses;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\libpng;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\glad\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\simpleini\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)pcsx2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<!-- Needed for moc pch -->
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(ProjectDir)\Settings;$(ProjectDir)\GameList</AdditionalIncludeDirectories>
<ExceptionHandling>Async</ExceptionHandling>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;LZMA_API_STATIC;BUILD_DX=1;SPU2X_PORTAUDIO;DIRECTINPUT_VERSION=0x0800;PCSX2_CORE;DISABLE_RECORDING;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Debug))">PCSX2_DEBUG;PCSX2_DEVBUILD;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Devel))">PCSX2_DEVEL;PCSX2_DEVBUILD;NDEBUG;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Release))">NDEBUG;_SECURE_SCL_=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(CI)'=='true'">PCSX2_CI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="!$(Configuration.Contains(AVX2))">_M_SSE=0x401;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(AVX2))">_M_SSE=0x501;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<!-- This flag will throw a warning on x64 as SSE2 is implied-->
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
<EnableEnhancedInstructionSet Condition="'$(Platform)'!='x64'">StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<EnableEnhancedInstructionSet Condition="$(Configuration.Contains(AVX2))">AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<MinimalRebuild>false</MinimalRebuild>
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
<!-- SH 2/3 flashlight, explicitly set here don't change -->
<!-- https://github.com/PCSX2/pcsx2/commit/16431653e4d92fda4069031897e24fbe4688d36a -->
<FloatingPointModel>Precise</FloatingPointModel>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalOptions>/Zc:__cplusplus /Zo /utf-8%(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<LargeAddressAware>Yes</LargeAddressAware>
<AdditionalDependencies>comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;rpcrt4.lib;iphlpapi.lib;dsound.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dxguid.lib;dinput8.lib;hid.lib;PowrProf.lib;d3dcompiler.lib;d3d11.lib;dxgi.lib;strmiids.lib;opengl32.lib;comsuppw.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ResourceCompile Include="$(SolutionDir)3rdparty\wxwidgets3.0\include\wx\msw\wx.rc">
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\wxwidgets3.0\$(PlatformName);$(SolutionDir)3rdparty\wxwidgets3.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<ResourceCompile Include="..\pcsx2\PCSX2.rc" />
<ResourceCompile Include="..\pcsx2\GS\GS.rc" />
<ResourceCompile Include="..\pcsx2\PAD\Windows\PAD.rc" />
<ResourceCompile Include="..\pcsx2\SPU2\Windows\SPU2.rc" />
<ResourceCompile Include="..\pcsx2\USB\usb-pad\dx\versionproxy.rc" />
<ResourceCompile Include="..\pcsx2\USB\usb-pad\raw\raw-config.rc" />
<ResourceCompile Include="..\pcsx2\USB\Win32\USBDialog.rc" />
<ResourceCompile Include="..\pcsx2\windows\wxResources.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)3rdparty\baseclasses\baseclasses.vcxproj">
<Project>{27f17499-a372-4408-8afa-4f9f4584fbd3}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\fmt\fmt.vcxproj">
<Project>{449ad25e-424a-4714-babc-68706cdcc33b}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\libjpeg\libjpeg.vcxproj">
<Project>{bc236261-77e8-4567-8d09-45cd02965eb6}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\libpng\projects\vstudio\libpng\libpng.vcxproj">
<Project>{d6973076-9317-4ef2-a0b8-b7a18ac0713e}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\libsamplerate\libsamplerate.vcxproj">
<Project>{47afdbef-f15f-4bc0-b436-5be443c3f80f}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\pthreads4w\build\pthreads4w.vcxproj">
<Project>{0fae817d-9a32-4830-857e-81da57246e16}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\soundtouch\SoundTouch.vcxproj">
<Project>{e9b51944-7e6d-4bcd-83f2-7bbd5a46182d}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\wxwidgets3.0\build\msw\wx30_base.vcxproj">
<Project>{3fcc50c2-81e9-5db2-b8d8-2129427568b1}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\xz\liblzma.vcxproj">
<Project>{12728250-16ec-4dc6-94d7-e21dd88947f8}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\libchdr\libchdr.vcxproj">
<Project>{a0d2b3ad-1f72-4ee3-8b5c-f2c358da35f0}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\zlib\zlib.vcxproj">
<Project>{2f6c0388-20cb-4242-9f6c-a6ebb6a83f47}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)tools\bin2cpp\bin2c.vcxproj">
<Project>{677b7d11-d5e1-40b3-88b1-9a4df83d2213}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\jpgd\jpgd.vcxproj">
<Project>{ed2f21fd-0a36-4a8f-9b90-e7d92a2acb63}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\imgui\imgui.vcxproj">
<Project>{88fb34ec-845e-4f21-a552-f1573b9ed167}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)common\common.vcxproj">
<Project>{4639972e-424e-4e13-8b07-ca403c481346}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)pcsx2\pcsx2core.vcxproj">
<Project>{6c7986c4-3e4d-4dcc-b3c6-6bb12b238995}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\glad\glad.vcxproj">
<Project>{c0293b32-5acf-40f0-aa6c-e6da6f3bf33a}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Manifest Include="..\pcsx2\windows\PCSX2.manifest" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Settings\BIOSSettingsWidget.cpp" />
<ClCompile Include="Settings\ControllerBindingWidgets.cpp" />
<ClCompile Include="Settings\ControllerGlobalSettingsWidget.cpp" />
<ClCompile Include="Settings\EmulationSettingsWidget.cpp" />
<ClCompile Include="Settings\GameListSettingsWidget.cpp" />
<ClCompile Include="Settings\GraphicsSettingsWidget.cpp" />
<ClCompile Include="Settings\InterfaceSettingsWidget.cpp" />
<ClCompile Include="Settings\SystemSettingsWidget.cpp" />
<ClCompile Include="Settings\SettingsDialog.cpp" />
<ClCompile Include="Settings\AdvancedSystemSettingsWidget.cpp" />
<ClCompile Include="Settings\GameFixSettingsWidget.cpp" />
<ClCompile Include="Settings\HotkeySettingsWidget.cpp" />
<ClCompile Include="Settings\InputBindingDialog.cpp" />
<ClCompile Include="Settings\InputBindingWidget.cpp" />
<ClCompile Include="Settings\ControllerSettingsDialog.cpp" />
<ClCompile Include="GameList\GameListModel.cpp" />
<ClCompile Include="GameList\GameListRefreshThread.cpp" />
<ClCompile Include="GameList\GameListWidget.cpp" />
<ClCompile Include="AboutDialog.cpp" />
<ClCompile Include="DisplayWidget.cpp" />
<ClCompile Include="QtHost.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="MainWindow.cpp" />
<ClCompile Include="PrecompiledHeader.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="EmuThread.cpp" />
<ClCompile Include="QtKeyCodes.cpp" />
<ClCompile Include="QtUtils.cpp" />
</ItemGroup>
<ItemGroup>
<QtMoc Include="Settings\SystemSettingsWidget.h" />
<QtMoc Include="Settings\InterfaceSettingsWidget.h" />
<QtMoc Include="Settings\GameListSettingsWidget.h" />
<QtMoc Include="Settings\BIOSSettingsWidget.h" />
<QtMoc Include="Settings\EmulationSettingsWidget.h" />
<QtMoc Include="Settings\GraphicsSettingsWidget.h" />
<QtMoc Include="Settings\SettingsDialog.h" />
<QtMoc Include="Settings\AdvancedSystemSettingsWidget.h" />
<QtMoc Include="Settings\GameFixSettingsWidget.h" />
<QtMoc Include="Settings\HotkeySettingsWidget.h" />
<QtMoc Include="Settings\InputBindingDialog.h" />
<QtMoc Include="Settings\InputBindingWidget.h" />
<QtMoc Include="Settings\ControllerSettingsDialog.h" />
<QtMoc Include="GameList\GameListModel.h" />
<QtMoc Include="GameList\GameListWidget.h" />
<QtMoc Include="GameList\GameListRefreshThread.h" />
<ClInclude Include="QtUtils.h" />
<QtMoc Include="Settings\ControllerBindingWidgets.h" />
<QtMoc Include="Settings\ControllerGlobalSettingsWidget.h" />
<ClInclude Include="SettingWidgetBinder.h" />
<ClInclude Include="QtHost.h" />
<ClInclude Include="PrecompiledHeader.h" />
<QtMoc Include="AboutDialog.h" />
<QtMoc Include="EmuThread.h" />
<QtMoc Include="MainWindow.h" />
<QtMoc Include="DisplayWidget.h" />
</ItemGroup>
<ItemGroup>
<QtResource Include="resources\resources.qrc">
<FileType>Document</FileType>
</QtResource>
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(IntDir)Settings\moc_BIOSSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_ControllerBindingWidgets.cpp" />
<ClCompile Include="x64\Devel\Settings\moc_ControllerGlobalSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_ControllerSettingsDialog.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_EmulationSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_GameListSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_GraphicsSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_InterfaceSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_SystemSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_SettingsDialog.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_AdvancedSystemSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_GameFixSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_HotkeySettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_InputBindingDialog.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_InputBindingWidget.cpp" />
<ClCompile Include="$(IntDir)GameList\moc_GameListModel.cpp" />
<ClCompile Include="$(IntDir)GameList\moc_GameListRefreshThread.cpp" />
<ClCompile Include="$(IntDir)GameList\moc_GameListWidget.cpp" />
<ClCompile Include="$(IntDir)moc_AboutDialog.cpp" />
<ClCompile Include="$(IntDir)moc_DisplayWidget.cpp" />
<ClCompile Include="$(IntDir)moc_EmuThread.cpp" />
<ClCompile Include="$(IntDir)moc_MainWindow.cpp" />
<ClCompile Include="$(IntDir)qrc_resources.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<QtUi Include="MainWindow.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\SettingsDialog.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\SystemSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\GameListSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\BIOSSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\EmulationSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\GraphicsSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\InterfaceSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\AdvancedSystemSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\GameFixSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\InputBindingDialog.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\ControllerSettingsDialog.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\ControllerBindingWidget_DualShock2.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\ControllerBindingWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\ControllerGlobalSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(SolutionDir)common\vsprops\QtCompile.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

View File

@ -0,0 +1,301 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Resources">
<UniqueIdentifier>{1f18feb4-85f0-455d-927a-d4d6b226d8a5}</UniqueIdentifier>
</Filter>
<Filter Include="moc">
<UniqueIdentifier>{1ab68559-2163-40b5-818b-d2a7ff210c12}</UniqueIdentifier>
</Filter>
<Filter Include="Settings">
<UniqueIdentifier>{11eec1ee-70c1-42ad-8cd1-e7f72f4c8673}</UniqueIdentifier>
</Filter>
<Filter Include="GameList">
<UniqueIdentifier>{aff229ec-39ea-40d4-b1c9-b5c4a932a2e0}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="$(SolutionDir)3rdparty\wxwidgets3.0\include\wx\msw\wx.rc">
<Filter>Resources</Filter>
</ResourceCompile>
<ResourceCompile Include="..\pcsx2\GS\GS.rc">
<Filter>Resources</Filter>
</ResourceCompile>
<ResourceCompile Include="..\pcsx2\PAD\Windows\PAD.rc">
<Filter>Resources</Filter>
</ResourceCompile>
<ResourceCompile Include="..\pcsx2\PCSX2.rc">
<Filter>Resources</Filter>
</ResourceCompile>
<ResourceCompile Include="..\pcsx2\USB\usb-pad\raw\raw-config.rc">
<Filter>Resources</Filter>
</ResourceCompile>
<ResourceCompile Include="..\pcsx2\SPU2\Windows\SPU2.rc">
<Filter>Resources</Filter>
</ResourceCompile>
<ResourceCompile Include="..\pcsx2\USB\Win32\USBDialog.rc">
<Filter>Resources</Filter>
</ResourceCompile>
<ResourceCompile Include="..\pcsx2\USB\usb-pad\dx\versionproxy.rc">
<Filter>Resources</Filter>
</ResourceCompile>
<ResourceCompile Include="..\pcsx2\windows\wxResources.rc">
<Filter>Resources</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="PrecompiledHeader.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="QtHost.cpp" />
<ClCompile Include="MainWindow.cpp" />
<ClCompile Include="$(IntDir)moc_MainWindow.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)qrc_resources.cpp">
<Filter>Resources</Filter>
</ClCompile>
<ClCompile Include="DisplayWidget.cpp" />
<ClCompile Include="$(IntDir)moc_DisplayWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="EmuThread.cpp" />
<ClCompile Include="QtUtils.cpp" />
<ClCompile Include="$(IntDir)moc_EmuThread.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="QtKeyCodes.cpp" />
<ClCompile Include="Settings\BIOSSettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\EmulationSettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\GameListSettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\GraphicsSettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\InterfaceSettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\SettingsDialog.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\SystemSettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_BIOSSettingsWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_EmulationSettingsWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_GameListSettingsWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_GraphicsSettingsWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_InterfaceSettingsWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_SettingsDialog.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_SystemSettingsWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_AdvancedSystemSettingsWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="Settings\AdvancedSystemSettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_GameFixSettingsWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="Settings\GameFixSettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_HotkeySettingsWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_InputBindingDialog.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_InputBindingWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="Settings\InputBindingWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\HotkeySettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\InputBindingDialog.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="AboutDialog.cpp" />
<ClCompile Include="GameList\GameListRefreshThread.cpp">
<Filter>GameList</Filter>
</ClCompile>
<ClCompile Include="GameList\GameListWidget.cpp">
<Filter>GameList</Filter>
</ClCompile>
<ClCompile Include="GameList\GameListModel.cpp">
<Filter>GameList</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)moc_AboutDialog.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_ControllerSettingsDialog.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)GameList\moc_GameListModel.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)GameList\moc_GameListRefreshThread.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)GameList\moc_GameListWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="Settings\ControllerSettingsDialog.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\ControllerBindingWidgets.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_ControllerBindingWidgets.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="Settings\ControllerGlobalSettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="x64\Devel\Settings\moc_ControllerGlobalSettingsWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
<Filter>Resources</Filter>
</Manifest>
</ItemGroup>
<ItemGroup>
<ClInclude Include="PrecompiledHeader.h" />
<ClInclude Include="QtHost.h" />
<ClInclude Include="QtUtils.h" />
<ClInclude Include="SettingWidgetBinder.h" />
</ItemGroup>
<ItemGroup>
<QtMoc Include="MainWindow.h" />
<QtMoc Include="DisplayWidget.h" />
<QtMoc Include="EmuThread.h" />
<QtMoc Include="Settings\BIOSSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\EmulationSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\GameListSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\GraphicsSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\InterfaceSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\SettingsDialog.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\SystemSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\AdvancedSystemSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\GameFixSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\HotkeySettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\InputBindingDialog.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\InputBindingWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="AboutDialog.h" />
<QtMoc Include="GameList\GameListWidget.h">
<Filter>GameList</Filter>
</QtMoc>
<QtMoc Include="GameList\GameListModel.h">
<Filter>GameList</Filter>
</QtMoc>
<QtMoc Include="GameList\GameListRefreshThread.h">
<Filter>GameList</Filter>
</QtMoc>
<QtMoc Include="Settings\ControllerSettingsDialog.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\ControllerBindingWidgets.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\ControllerGlobalSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
</ItemGroup>
<ItemGroup>
<QtResource Include="resources\resources.qrc">
<Filter>Resources</Filter>
</QtResource>
</ItemGroup>
<ItemGroup>
<QtUi Include="mainwindow.ui" />
<QtUi Include="Settings\BIOSSettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\EmulationSettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\GameListSettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\GraphicsSettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\InterfaceSettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\SystemSettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\SettingsDialog.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\AdvancedSystemSettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\GameFixSettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\InputBindingDialog.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\ControllerSettingsDialog.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\ControllerBindingWidget_DualShock2.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\ControllerBindingWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\ControllerGlobalSettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
</ItemGroup>
</Project>

View File

@ -0,0 +1,13 @@
#!/bin/sh
IFS="
"
printf "<RCC>\n"
printf "\t<qresource>\n"
for i in $(find . -not -iname '*.sh' -not -iname '*.qrc' -type f | cut -d'/' -f2-99); do
printf "\t\t<file>%s</file>\n" "$i"
done
printf "\t</qresource>\n"
printf "</RCC>\n"

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B

Some files were not shown because too many files have changed in this diff Show More