mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-31 11:18:41 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3695862368 | ||
|
|
18ae23b99d | ||
|
|
bb60058fa0 | ||
|
|
1ad25605d1 | ||
|
|
9809265be4 | ||
|
|
63872e6b28 | ||
|
|
fb3a9eae9b | ||
|
|
f53c3050df | ||
|
|
67bd0dfcdb | ||
|
|
12196359f7 | ||
|
|
609165e412 | ||
|
|
41f14a8cf8 | ||
|
|
a8bdd3fbfc | ||
|
|
993ec82a9e | ||
|
|
c5a2844367 | ||
|
|
e5bb405b47 | ||
|
|
8c9a65d094 | ||
|
|
047b8593ac | ||
|
|
4fc4eb8a66 | ||
|
|
1f95a86f0a | ||
|
|
2b90451c4a | ||
|
|
77a6525556 | ||
|
|
5eacab387d | ||
|
|
ddaf57d5b0 | ||
|
|
1144c46109 | ||
|
|
850b839fc3 | ||
|
|
22037e75ba | ||
|
|
303ab163ab | ||
|
|
2833537167 | ||
|
|
1aa7b591b6 | ||
|
|
2f0463d936 | ||
|
|
82a1ec0c3a | ||
|
|
d65133451d | ||
|
|
36e81949e0 | ||
|
|
6b62945632 | ||
|
|
fa2f578900 | ||
|
|
e1c9987059 | ||
|
|
325e219bb1 | ||
|
|
be208df11b | ||
|
|
49df804d1b | ||
|
|
122fde79bd | ||
|
|
2099e68c41 | ||
|
|
52ccc609cd | ||
|
|
b402f6a404 | ||
|
|
3576a1824d | ||
|
|
c3afaae169 | ||
|
|
c5a9ce6b56 | ||
|
|
4f0d944bb9 | ||
|
|
5684bcb6f4 | ||
|
|
5087fcea88 | ||
|
|
28f984e87f | ||
|
|
e0233daeb0 | ||
|
|
49922ebe32 | ||
|
|
8fe0c3441c | ||
|
|
ba55caa404 | ||
|
|
e50e651078 | ||
|
|
39b4fd47c7 | ||
|
|
56b83e5cfa | ||
|
|
ed57355948 | ||
|
|
b4b2f3a0b6 | ||
|
|
1946882952 | ||
|
|
dbe4930c17 | ||
|
|
3b25fa3065 | ||
|
|
01849565aa | ||
|
|
e3ca5833d0 | ||
|
|
dfac1f034b | ||
|
|
a8d07df81d | ||
|
|
609cb44b01 | ||
|
|
feb4d605d0 | ||
|
|
276d887917 | ||
|
|
61aef9c96f | ||
|
|
b4005682f2 | ||
|
|
7d98461fc6 | ||
|
|
862d03b78e | ||
|
|
0ecf46240f | ||
|
|
a2755e212b | ||
|
|
2ec5559dd6 | ||
|
|
6f904759ee | ||
|
|
507fafd601 | ||
|
|
9c463f1338 | ||
|
|
8818cd0285 | ||
|
|
23b72d08d2 | ||
|
|
227049b6f2 | ||
|
|
97abd3e1f9 | ||
|
|
6f34b7ba99 | ||
|
|
c0d86c3852 | ||
|
|
bf743ff467 | ||
|
|
306f994464 | ||
|
|
f56676942b | ||
|
|
bfd0a05289 | ||
|
|
3999c08f00 | ||
|
|
febb8ec1a6 | ||
|
|
cdd38ef7aa | ||
|
|
54c620a5df | ||
|
|
089b7fa73e | ||
|
|
d9d0e84ca1 | ||
|
|
badede2e2d | ||
|
|
e2ae28741d | ||
|
|
ff34150b15 | ||
|
|
4a93ceac58 | ||
|
|
5a724bf49e | ||
|
|
c23bcf6322 | ||
|
|
c863149ad9 | ||
|
|
5fb6e22bed | ||
|
|
d634088282 | ||
|
|
c99a935831 | ||
|
|
165da677ed | ||
|
|
0bbde2ca52 | ||
|
|
3d13c5d13c | ||
|
|
9d978c67ec | ||
|
|
8766e1fa57 | ||
|
|
c0e4883987 | ||
|
|
57f2cd5f9e | ||
|
|
50d8d06a94 | ||
|
|
2e07328878 | ||
|
|
ad8294e521 | ||
|
|
14426a7b45 | ||
|
|
6697e76be1 | ||
|
|
73cd876f6d | ||
|
|
e626754000 | ||
|
|
1fedd31229 | ||
|
|
bfe1746ddb | ||
|
|
4800c32db4 | ||
|
|
140fc28b3e | ||
|
|
f9833bb8af | ||
|
|
4b6ddaf09e | ||
|
|
d427db4a15 | ||
|
|
deb39cc20f | ||
|
|
3a4c25e916 | ||
|
|
f416eb3d4f | ||
|
|
87cbb1f90c | ||
|
|
68f43121fb | ||
|
|
51ceab1f3c | ||
|
|
2257992a3f | ||
|
|
40ead584d7 | ||
|
|
6f2be7bd17 |
@@ -64,7 +64,7 @@ jobs:
|
||||
run: |
|
||||
sudo rm -f /etc/apt/sources.list.d/ubuntu-toolchain-r-ubuntu-test-jammy.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --allow-downgrades libc6=2.35-0ubuntu3.5 libc6-dev=2.35-0ubuntu3.5 libstdc++6=12.3.0-1ubuntu1~22.04 libgcc-s1=12.3.0-1ubuntu1~22.04
|
||||
sudo apt-get install -y --allow-downgrades 'libc6=2.35-0ubuntu*' 'libc6-dev=2.35-0ubuntu*' libstdc++6=12.3.0-1ubuntu1~22.04 libgcc-s1=12.3.0-1ubuntu1~22.04
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
|
||||
- name: Build Dependencies
|
||||
if: steps.cache-deps.outputs.cache-hit != 'true'
|
||||
run: .github/workflows/scripts/linux/build-dependencies-qt.sh
|
||||
run: .github/workflows/scripts/linux/build-dependencies-qt.sh "$HOME/deps"
|
||||
|
||||
- name: Download patches
|
||||
run: |
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
|
||||
set -e
|
||||
|
||||
INSTALLDIR="$HOME/deps"
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Syntax: $0 <output directory>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INSTALLDIR="$1"
|
||||
NPROCS="$(getconf _NPROCESSORS_ONLN)"
|
||||
SDL=SDL2-2.28.5
|
||||
QT=6.6.1
|
||||
|
||||
+13
-4
@@ -56,6 +56,9 @@ oprofile_data/
|
||||
/UpgradeLog*.htm
|
||||
/.vscode*
|
||||
|
||||
# Jetbrains Rider
|
||||
/.idea*
|
||||
|
||||
# KDevelop 4 Workspace Configuration Files
|
||||
*.kdev4
|
||||
/.kdev4*
|
||||
@@ -77,6 +80,7 @@ oprofile_data/
|
||||
/bin/gamesettings
|
||||
/bin/help
|
||||
/bin/inis
|
||||
/bin/inis/debuggersettings
|
||||
/bin/logs
|
||||
/bin/memcards
|
||||
/bin/plugins
|
||||
@@ -85,12 +89,17 @@ oprofile_data/
|
||||
/bin/textures
|
||||
/bin/translations
|
||||
/bin/inputprofiles
|
||||
/bin/videos
|
||||
/bin/portable.ini
|
||||
|
||||
# Manually added by user.
|
||||
/bin/resources/patches.zip
|
||||
|
||||
# Resources that are runtime downloaded.
|
||||
/bin/resources/NotoSansJP-Regular.ttf
|
||||
/bin/resources/NotoSansKR-Regular.ttf
|
||||
/bin/resources/NotoSansSC-Regular.ttf
|
||||
/bin/resources/NotoSansTC-Regular.ttf
|
||||
/bin/resources/fonts/NotoSansJP-Regular.ttf
|
||||
/bin/resources/fonts/NotoSansKR-Regular.ttf
|
||||
/bin/resources/fonts/NotoSansSC-Regular.ttf
|
||||
/bin/resources/fonts/NotoSansTC-Regular.ttf
|
||||
|
||||
/deps
|
||||
/ipch
|
||||
|
||||
Vendored
+1
@@ -706,6 +706,7 @@
|
||||
#define ICON_FA_RANDOM "\xef\x81\xb4" // U+f074
|
||||
#define ICON_FA_RECEIPT "\xef\x95\x83" // U+f543
|
||||
#define ICON_FA_RECORD_VINYL "\xef\xa3\x99" // U+f8d9
|
||||
#define ICON_FA_RECORDING "\xef\xa3\x9a" // U+f8da
|
||||
#define ICON_FA_RECYCLE "\xef\x86\xb8" // U+f1b8
|
||||
#define ICON_FA_REDO "\xef\x80\x9e" // U+f01e
|
||||
#define ICON_FA_REDO_ALT "\xef\x8b\xb9" // U+f2f9
|
||||
|
||||
Vendored
+1428
-1142
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
RunWizard=0
|
||||
+630
-68
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -314,6 +314,7 @@
|
||||
03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows,
|
||||
03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows,
|
||||
03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows,
|
||||
03000000242e00006a48000000000000,Hyperkin RetroN Sq,a:b3,b:b7,back:b5,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b0,rightshoulder:b1,start:b4,x:b2,y:b6,platform:Windows,
|
||||
03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Windows,
|
||||
03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,
|
||||
03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
@@ -352,7 +353,7 @@
|
||||
030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,
|
||||
030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,lefttrigger:a2,righttrigger:a5,platform:Windows,
|
||||
030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000006d0400001ec2000000000000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000006d04000019c2000000000000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -461,7 +462,7 @@
|
||||
030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
|
||||
03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,
|
||||
03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,
|
||||
03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
030000006f0e00008501000000000000,PDP Fightpad Pro GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
@@ -612,6 +613,7 @@
|
||||
03000000050b00001a1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
|
||||
03000000050b00001c1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
|
||||
030000004f04000001d0000000000000,Rumble Force,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
|
||||
030000000d0f0000ad00000000000000,RX Gamepad,a:b0,b:b4,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b6,start:b9,x:b2,y:b1,platform:Windows,
|
||||
030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -678,6 +680,7 @@
|
||||
03000000457500002211000000000000,Szmy Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000004f0400000ab1000000000000,T16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows,
|
||||
030000000d0f00007b00000000000000,TAC GEAR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000e40a00000307000000000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows,
|
||||
03000000e40a00000207000000000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows,
|
||||
03000000d814000001a0000000000000,TE Kitty,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
@@ -1018,6 +1021,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
|
||||
030000000d0f0000f600000000010000,Switch Hori Pad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000e40a00000307000001000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,
|
||||
03000000e40a00000207000001000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,
|
||||
03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X,
|
||||
@@ -1169,15 +1174,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000c21100000791000011010000,Be1 GC101 Controller 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000c31100000791000011010000,Be1 GC101 Controller 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400008e02000003030000,Be1 GC101 Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000bc2000004d50000011010000,BEITONG A1T2 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000bc2000000055000001000000,BETOP AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000bc2000004d50000011010000,Beitong A1T2 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000bc2000000055000001000000,Betop AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000af1e00002400000010010000,ClockworkPI DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,
|
||||
03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1261,6 +1266,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000830500006020000010010000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
|
||||
030000008f0e00001330000001010000,iCode Retro Adapter,b:b3,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b1,start:b7,x:b2,y:b0,platform:Linux,
|
||||
050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
|
||||
03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,
|
||||
@@ -1573,6 +1579,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000457500000401000011010000,SZMY Power DS4 Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000457500002211000010010000,SZMY Power Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000008f0e00001431000010010000,SZMY Power PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000e40a00000307000011010000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux,
|
||||
03000000e40a00000207000011010000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux,
|
||||
03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux,
|
||||
03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000591c00002400000010010000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 98 KiB |
@@ -631,7 +631,7 @@ float4 sample_color(float2 st, float uv_w)
|
||||
}
|
||||
else if(PS_AEM_FMT == FMT_16)
|
||||
{
|
||||
c[i].a = c[i].a >= 0.5 ? TA.y : !PS_AEM || any(c[i].rgb) ? TA.x : 0;
|
||||
c[i].a = c[i].a >= 0.5 ? TA.y : !PS_AEM || any(int3(c[i].rgb * 255.0f) & 0xF8) ? TA.x : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -580,7 +580,7 @@ vec4 sample_color(vec2 st)
|
||||
c[i].a = ( (PS_AEM == 0) || any(bvec3(c[i].rgb)) ) ? TA.x : 0.0f;
|
||||
//c[i].a = ( (PS_AEM == 0) || (sum > 0.0f) ) ? TA.x : 0.0f;
|
||||
#elif (PS_AEM_FMT == FMT_16)
|
||||
c[i].a = c[i].a >= 0.5 ? TA.y : ( (PS_AEM == 0) || any(bvec3(c[i].rgb)) ) ? TA.x : 0.0f;
|
||||
c[i].a = c[i].a >= 0.5 ? TA.y : ( (PS_AEM == 0) || any(bvec3(ivec3(c[i].rgb * 255.0f) & ivec3(0xF8))) ) ? TA.x : 0.0f;
|
||||
//c[i].a = c[i].a >= 0.5 ? TA.y : ( (PS_AEM == 0) || (sum > 0.0f) ) ? TA.x : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -817,7 +817,7 @@ vec4 sample_color(vec2 st)
|
||||
#if (PS_AEM_FMT == FMT_24)
|
||||
c[i].a = (PS_AEM == 0 || any(bvec3(c[i].rgb))) ? TA.x : 0.0f;
|
||||
#elif (PS_AEM_FMT == FMT_16)
|
||||
c[i].a = (c[i].a >= 0.5) ? TA.y : ((PS_AEM == 0 || any(bvec3(c[i].rgb))) ? TA.x : 0.0f);
|
||||
c[i].a = (c[i].a >= 0.5) ? TA.y : ((PS_AEM == 0 || any(bvec3(ivec3(c[i].rgb * 255.0f) & ivec3(0xF8)))) ? TA.x : 0.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ set(PCSX2_DEFS "")
|
||||
#-------------------------------------------------------------------------------
|
||||
# Misc option
|
||||
#-------------------------------------------------------------------------------
|
||||
option(DISABLE_BUILD_DATE "Disable including the binary compile date")
|
||||
option(ENABLE_TESTS "Enables building the unit tests" ON)
|
||||
option(LTO_PCSX2_CORE "Enable LTO/IPO/LTCG on the subset of pcsx2 that benefits most from it but not anything else")
|
||||
option(USE_VTUNE "Plug VTUNE to profile GS JIT.")
|
||||
@@ -231,11 +230,6 @@ endif()
|
||||
|
||||
set(PCSX2_WARNINGS ${DEFAULT_WARNINGS})
|
||||
|
||||
if(DISABLE_BUILD_DATE)
|
||||
message(STATUS "Disabling the inclusion of the binary compile date.")
|
||||
list(APPEND PCSX2_DEFS DISABLE_BUILD_DATE)
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# MacOS-specific things
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
+50
-47
@@ -1,7 +1,12 @@
|
||||
function(detect_operating_system)
|
||||
message(STATUS "CMake Version: ${CMAKE_VERSION}")
|
||||
message(STATUS "CMake System Name: ${CMAKE_SYSTEM_NAME}")
|
||||
|
||||
# LINUX wasn't added until CMake 3.25.
|
||||
if (CMAKE_VERSION VERSION_LESS 3.25.0 AND CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
# Have to make it visible in this scope as well for below.
|
||||
set(LINUX TRUE PARENT_SCOPE)
|
||||
set(LINUX TRUE)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
@@ -39,19 +44,11 @@ function(detect_compiler)
|
||||
endfunction()
|
||||
|
||||
function(get_git_version_info)
|
||||
set(PCSX2_WC_TIME 0)
|
||||
set(PCSX2_GIT_REV "")
|
||||
set(PCSX2_GIT_TAG "")
|
||||
set(PCSX2_GIT_HASH "")
|
||||
if (GIT_FOUND AND EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} show -s --format=%ci HEAD
|
||||
OUTPUT_VARIABLE PCSX2_WC_TIME
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
# Output: "YYYY-MM-DD HH:MM:SS +HHMM" (last part is time zone, offset from UTC)
|
||||
string(REGEX REPLACE "[%:\\-]" "" PCSX2_WC_TIME "${PCSX2_WC_TIME}")
|
||||
string(REGEX REPLACE "([0-9]+) ([0-9]+).*" "\\1\\2" PCSX2_WC_TIME "${PCSX2_WC_TIME}")
|
||||
|
||||
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} describe
|
||||
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} describe --tags
|
||||
OUTPUT_VARIABLE PCSX2_GIT_REV
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET)
|
||||
@@ -78,58 +75,61 @@ function(get_git_version_info)
|
||||
OUTPUT_VARIABLE PCSX2_GIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET)
|
||||
|
||||
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} log -1 --format=%cd --date=local
|
||||
OUTPUT_VARIABLE PCSX2_GIT_DATE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET)
|
||||
endif()
|
||||
if ("${PCSX2_GIT_TAG}" MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" PCSX2_VERSION_LONG "${PCSX2_GIT_TAG}")
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" PCSX2_VERSION_SHORT "${PCSX2_GIT_TAG}")
|
||||
elseif(PCSX2_GIT_REV)
|
||||
set(PCSX2_VERSION_LONG "${PCSX2_GIT_REV}")
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?(-[a-z][a-z0-9]+)?" PCSX2_VERSION_SHORT "${PCSX2_VERSION_LONG}")
|
||||
else()
|
||||
set(PCSX2_VERSION_LONG "Unknown (git unavailable)")
|
||||
set(PCSX2_VERSION_SHORT "Unknown")
|
||||
endif()
|
||||
if ("${PCSX2_WC_TIME}" STREQUAL "")
|
||||
set(PCSX2_WC_TIME 0)
|
||||
if (NOT PCSX2_GIT_REV)
|
||||
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
|
||||
OUTPUT_VARIABLE PCSX2_GIT_REV
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET)
|
||||
if (NOT PCSX2_GIT_REV)
|
||||
set(PCSX2_GIT_REV "Unknown")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(PCSX2_WC_TIME "${PCSX2_WC_TIME}" PARENT_SCOPE)
|
||||
set(PCSX2_GIT_REV "${PCSX2_GIT_REV}" PARENT_SCOPE)
|
||||
set(PCSX2_GIT_TAG "${PCSX2_GIT_TAG}" PARENT_SCOPE)
|
||||
set(PCSX2_GIT_HASH "${PCSX2_GIT_HASH}" PARENT_SCOPE)
|
||||
set(PCSX2_VERSION_LONG "${PCSX2_VERSION_LONG}" PARENT_SCOPE)
|
||||
set(PCSX2_VERSION_SHORT "${PCSX2_VERSION_SHORT}" PARENT_SCOPE)
|
||||
set(PCSX2_GIT_DATE "${PCSX2_GIT_DATE}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(write_svnrev_h)
|
||||
if(PCSX2_GIT_TAG)
|
||||
if ("${PCSX2_GIT_TAG}" MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
|
||||
"#define SVN_REV ${PCSX2_WC_TIME}ll\n"
|
||||
"#define GIT_TAG \"${PCSX2_GIT_TAG}\"\n"
|
||||
"#define GIT_TAGGED_COMMIT 1\n"
|
||||
"#define GIT_TAG_HI ${CMAKE_MATCH_1}\n"
|
||||
"#define GIT_TAG_MID ${CMAKE_MATCH_2}\n"
|
||||
"#define GIT_TAG_LO ${CMAKE_MATCH_3}\n"
|
||||
"#define GIT_REV \"\"\n"
|
||||
"#define GIT_HASH \"${PCSX2_GIT_HASH}\"\n"
|
||||
)
|
||||
else()
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
|
||||
"#define SVN_REV ${PCSX2_WC_TIME}ll\n"
|
||||
"#define GIT_TAG \"${PCSX2_GIT_TAG}\"\n"
|
||||
"#define GIT_TAGGED_COMMIT 1\n"
|
||||
"#define GIT_REV \"\"\n"
|
||||
"#define GIT_HASH \"${PCSX2_GIT_HASH}\"\n"
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
if ("${PCSX2_GIT_TAG}" MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
|
||||
"#define GIT_TAG \"${PCSX2_GIT_TAG}\"\n"
|
||||
"#define GIT_TAGGED_COMMIT 1\n"
|
||||
"#define GIT_TAG_HI ${CMAKE_MATCH_1}\n"
|
||||
"#define GIT_TAG_MID ${CMAKE_MATCH_2}\n"
|
||||
"#define GIT_TAG_LO ${CMAKE_MATCH_3}\n"
|
||||
"#define GIT_REV \"${PCSX2_GIT_TAG}\"\n"
|
||||
"#define GIT_HASH \"${PCSX2_GIT_HASH}\"\n"
|
||||
"#define GIT_DATE \"${PCSX2_GIT_DATE}\"\n"
|
||||
)
|
||||
elseif ("${PCSX2_GIT_REV}" MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)")
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
|
||||
"#define SVN_REV ${PCSX2_WC_TIME}ll\n"
|
||||
"#define GIT_TAG \"${PCSX2_GIT_TAG}\"\n"
|
||||
"#define GIT_TAGGED_COMMIT 0\n"
|
||||
"#define GIT_TAG_HI ${CMAKE_MATCH_1}\n"
|
||||
"#define GIT_TAG_MID ${CMAKE_MATCH_2}\n"
|
||||
"#define GIT_TAG_LO ${CMAKE_MATCH_3}\n"
|
||||
"#define GIT_REV \"${PCSX2_GIT_REV}\"\n"
|
||||
"#define GIT_HASH \"${PCSX2_GIT_HASH}\"\n"
|
||||
"#define GIT_DATE \"${PCSX2_GIT_DATE}\"\n"
|
||||
)
|
||||
else()
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
|
||||
"#define GIT_TAG \"${PCSX2_GIT_TAG}\"\n"
|
||||
"#define GIT_TAGGED_COMMIT 0\n"
|
||||
"#define GIT_TAG_HI 0\n"
|
||||
"#define GIT_TAG_MID 0\n"
|
||||
"#define GIT_TAG_LO 0\n"
|
||||
"#define GIT_REV \"${PCSX2_GIT_REV}\"\n"
|
||||
"#define GIT_HASH \"${PCSX2_GIT_HASH}\"\n"
|
||||
"#define GIT_DATE \"${PCSX2_GIT_DATE}\"\n"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -213,6 +213,9 @@ function(fixup_file_properties target)
|
||||
if("${source}" MATCHES "\\.(inl|h)$")
|
||||
set_source_files_properties("${source}" PROPERTIES XCODE_EXPLICIT_FILE_TYPE sourcecode.cpp.h)
|
||||
endif()
|
||||
if("${source}" MATCHES "\\.(qm)$")
|
||||
set_source_files_properties("${source}" PROPERTIES XCODE_EXPLICIT_FILE_TYPE compiled)
|
||||
endif()
|
||||
# CMake makefile and ninja generators will attempt to share one PCH for both cpp and mm files
|
||||
# That's not actually OK
|
||||
if("${source}" MATCHES "\\.mm$")
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace CocoaTools
|
||||
std::optional<std::string> MoveToTrash(std::string_view file);
|
||||
/// Launch the given application once this one quits
|
||||
bool DelayedLaunch(std::string_view file);
|
||||
/// Open a Finder window to the given URL
|
||||
bool ShowInFinder(std::string_view file);
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
+15
-2
@@ -17,6 +17,11 @@
|
||||
|
||||
// MARK: - Metal Layers
|
||||
|
||||
static NSString*_Nonnull NSStringFromStringView(std::string_view sv)
|
||||
{
|
||||
return [[NSString alloc] initWithBytes:sv.data() length:sv.size() encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
bool CocoaTools::CreateMetalLayer(WindowInfo* wi)
|
||||
{
|
||||
if (![NSThread isMainThread])
|
||||
@@ -156,7 +161,7 @@ std::optional<std::string> CocoaTools::GetNonTranslocatedBundlePath()
|
||||
|
||||
std::optional<std::string> CocoaTools::MoveToTrash(std::string_view file)
|
||||
{
|
||||
NSURL* url = [NSURL fileURLWithPath:[[NSString alloc] initWithBytes:file.data() length:file.size() encoding:NSUTF8StringEncoding]];
|
||||
NSURL* url = [NSURL fileURLWithPath:NSStringFromStringView(file)];
|
||||
NSURL* new_url;
|
||||
if (![[NSFileManager defaultManager] trashItemAtURL:url resultingItemURL:&new_url error:nil])
|
||||
return std::nullopt;
|
||||
@@ -170,9 +175,17 @@ bool CocoaTools::DelayedLaunch(std::string_view file)
|
||||
[task setExecutableURL:[NSURL fileURLWithPath:@"/bin/sh"]];
|
||||
[task setEnvironment:@{
|
||||
@"WAITPID": [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]],
|
||||
@"LAUNCHAPP": [[NSString alloc] initWithBytes:file.data() length:file.size() encoding:NSUTF8StringEncoding],
|
||||
@"LAUNCHAPP": NSStringFromStringView(file),
|
||||
}];
|
||||
[task setArguments:@[@"-c", @"while /bin/ps -p $WAITPID > /dev/null; do /bin/sleep 0.1; done; exec /usr/bin/open \"$LAUNCHAPP\";"]];
|
||||
return [task launchAndReturnError:nil];
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Directory Services
|
||||
|
||||
bool CocoaTools::ShowInFinder(std::string_view file)
|
||||
{
|
||||
return [[NSWorkspace sharedWorkspace] selectFile:NSStringFromStringView(file)
|
||||
inFileViewerRootedAtPath:nil];
|
||||
}
|
||||
|
||||
@@ -271,6 +271,15 @@ cleanup:
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Log::IsDebugOutputAvailable()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return IsDebuggerPresent();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Log::IsDebugOutputEnabled()
|
||||
{
|
||||
return (s_console_level > LOGLEVEL_NONE);
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace Log
|
||||
void SetConsoleOutputLevel(LOGLEVEL level);
|
||||
|
||||
// adds a debug console output
|
||||
bool IsDebugOutputAvailable();
|
||||
bool IsDebugOutputEnabled();
|
||||
void SetDebugOutputLevel(LOGLEVEL level);
|
||||
|
||||
|
||||
+92
-56
@@ -1076,19 +1076,19 @@ static u32 TranslateWin32Attributes(u32 Win32Attributes)
|
||||
}
|
||||
|
||||
static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path, const char* path, const char* pattern,
|
||||
u32 flags, FileSystem::FindResultsArray* results)
|
||||
u32 flags, FileSystem::FindResultsArray* results, std::vector<std::string>& visited)
|
||||
{
|
||||
std::string tempStr;
|
||||
std::string search_dir;
|
||||
if (path)
|
||||
{
|
||||
if (parent_path)
|
||||
tempStr = StringUtil::StdStringFromFormat("%s\\%s\\%s\\*", origin_path, parent_path, path);
|
||||
search_dir = fmt::format("{}\\{}\\{}\\*", origin_path, parent_path, path);
|
||||
else
|
||||
tempStr = StringUtil::StdStringFromFormat("%s\\%s\\*", origin_path, path);
|
||||
search_dir = fmt::format("{}\\{}\\*", origin_path, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
tempStr = StringUtil::StdStringFromFormat("%s\\*", origin_path);
|
||||
search_dir = fmt::format("{}\\*", origin_path);
|
||||
}
|
||||
|
||||
// holder for utf-8 conversion
|
||||
@@ -1096,7 +1096,7 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
|
||||
std::string utf8_filename;
|
||||
utf8_filename.reserve((sizeof(wfd.cFileName) / sizeof(wfd.cFileName[0])) * 2);
|
||||
|
||||
HANDLE hFind = FindFirstFileW(StringUtil::UTF8StringToWideString(tempStr).c_str(), &wfd);
|
||||
const HANDLE hFind = FindFirstFileW(StringUtil::UTF8StringToWideString(search_dir).c_str(), &wfd);
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
@@ -1104,7 +1104,7 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
|
||||
bool hasWildCards = false;
|
||||
bool wildCardMatchAll = false;
|
||||
u32 nFiles = 0;
|
||||
if (std::strpbrk(pattern, "*?") != nullptr)
|
||||
if (std::strpbrk(pattern, "*?"))
|
||||
{
|
||||
hasWildCards = true;
|
||||
wildCardMatchAll = !(std::strcmp(pattern, "*"));
|
||||
@@ -1132,15 +1132,29 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
|
||||
{
|
||||
if (flags & FILESYSTEM_FIND_RECURSIVE)
|
||||
{
|
||||
// recurse into this directory
|
||||
if (parent_path != nullptr)
|
||||
{
|
||||
const std::string recurseDir = StringUtil::StdStringFromFormat("%s\\%s", parent_path, path);
|
||||
nFiles += RecursiveFindFiles(origin_path, recurseDir.c_str(), utf8_filename.c_str(), pattern, flags, results);
|
||||
}
|
||||
// check that we're not following an infinite symbolic link loop
|
||||
std::string real_recurse_dir;
|
||||
if (parent_path)
|
||||
real_recurse_dir = Path::RealPath(fmt::format("{}\\{}\\{}\\{}", origin_path, parent_path, path, utf8_filename));
|
||||
else if (path)
|
||||
real_recurse_dir = Path::RealPath(fmt::format("{}\\{}\\{}", origin_path, path, utf8_filename));
|
||||
else
|
||||
real_recurse_dir = Path::RealPath(fmt::format("{}\\{}", origin_path, utf8_filename));
|
||||
if (real_recurse_dir.empty() || std::find(visited.begin(), visited.end(), real_recurse_dir) == visited.end())
|
||||
{
|
||||
nFiles += RecursiveFindFiles(origin_path, path, utf8_filename.c_str(), pattern, flags, results);
|
||||
if (!real_recurse_dir.empty())
|
||||
visited.push_back(std::move(real_recurse_dir));
|
||||
|
||||
// recurse into this directory
|
||||
if (parent_path)
|
||||
{
|
||||
const std::string recurse_dir = fmt::format("{}\\{}", parent_path, path);
|
||||
nFiles += RecursiveFindFiles(origin_path, recurse_dir.c_str(), utf8_filename.c_str(), pattern, flags, results, visited);
|
||||
}
|
||||
else
|
||||
{
|
||||
nFiles += RecursiveFindFiles(origin_path, path, utf8_filename.c_str(), pattern, flags, results, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1171,23 +1185,21 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
|
||||
}
|
||||
|
||||
// add file to list
|
||||
// TODO string formatter, clean this mess..
|
||||
if (!(flags & FILESYSTEM_FIND_RELATIVE_PATHS))
|
||||
{
|
||||
if (parent_path != nullptr)
|
||||
outData.FileName =
|
||||
StringUtil::StdStringFromFormat("%s\\%s\\%s\\%s", origin_path, parent_path, path, utf8_filename.c_str());
|
||||
else if (path != nullptr)
|
||||
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s\\%s", origin_path, path, utf8_filename.c_str());
|
||||
if (parent_path)
|
||||
outData.FileName = fmt::format("{}\\{}\\{}\\{}", origin_path, parent_path, path, utf8_filename);
|
||||
else if (path)
|
||||
outData.FileName = fmt::format("{}\\{}\\{}", origin_path, path, utf8_filename);
|
||||
else
|
||||
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", origin_path, utf8_filename.c_str());
|
||||
outData.FileName = fmt::format("{}\\{}", origin_path, utf8_filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parent_path != nullptr)
|
||||
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s\\%s", parent_path, path, utf8_filename.c_str());
|
||||
else if (path != nullptr)
|
||||
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", path, utf8_filename.c_str());
|
||||
if (parent_path)
|
||||
outData.FileName = fmt::format("{}\\{}\\{}", parent_path, path, utf8_filename);
|
||||
else if (path)
|
||||
outData.FileName = fmt::format("{}\\{}", path, utf8_filename);
|
||||
else
|
||||
outData.FileName = utf8_filename;
|
||||
}
|
||||
@@ -1214,10 +1226,18 @@ bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, Fin
|
||||
if (!(flags & FILESYSTEM_FIND_KEEP_ARRAY))
|
||||
results->clear();
|
||||
|
||||
// enter the recursive function
|
||||
return (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results) > 0);
|
||||
}
|
||||
// add self if recursive, we don't want to visit it twice
|
||||
std::vector<std::string> visited;
|
||||
if (flags & FILESYSTEM_FIND_RECURSIVE)
|
||||
{
|
||||
std::string real_path = Path::RealPath(path);
|
||||
if (!real_path.empty())
|
||||
visited.push_back(std::move(real_path));
|
||||
}
|
||||
|
||||
// enter the recursive function
|
||||
return (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) > 0);
|
||||
}
|
||||
|
||||
static void TranslateStat64(struct stat* st, const struct _stat64& st64)
|
||||
{
|
||||
@@ -1620,23 +1640,23 @@ bool FileSystem::SetPathCompression(const char* path, bool enable)
|
||||
static_assert(sizeof(off_t) == sizeof(s64));
|
||||
|
||||
static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, const char* Path, const char* Pattern,
|
||||
u32 Flags, FileSystem::FindResultsArray* pResults)
|
||||
u32 Flags, FileSystem::FindResultsArray* pResults, std::vector<std::string>& visited)
|
||||
{
|
||||
std::string tempStr;
|
||||
if (Path)
|
||||
{
|
||||
if (ParentPath)
|
||||
tempStr = StringUtil::StdStringFromFormat("%s/%s/%s", OriginPath, ParentPath, Path);
|
||||
tempStr = fmt::format("{}/{}/{}", OriginPath, ParentPath, Path);
|
||||
else
|
||||
tempStr = StringUtil::StdStringFromFormat("%s/%s", OriginPath, Path);
|
||||
tempStr = fmt::format("{}/{}", OriginPath, Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
tempStr = StringUtil::StdStringFromFormat("%s", OriginPath);
|
||||
tempStr = fmt::format("{}", OriginPath);
|
||||
}
|
||||
|
||||
DIR* pDir = opendir(tempStr.c_str());
|
||||
if (pDir == nullptr)
|
||||
if (!pDir)
|
||||
return 0;
|
||||
|
||||
// small speed optimization for '*' case
|
||||
@@ -1663,12 +1683,12 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
|
||||
}
|
||||
|
||||
std::string full_path;
|
||||
if (ParentPath != nullptr)
|
||||
full_path = StringUtil::StdStringFromFormat("%s/%s/%s/%s", OriginPath, ParentPath, Path, pDirEnt->d_name);
|
||||
else if (Path != nullptr)
|
||||
full_path = StringUtil::StdStringFromFormat("%s/%s/%s", OriginPath, Path, pDirEnt->d_name);
|
||||
if (ParentPath)
|
||||
full_path = fmt::format("{}/{}/{}/{}", OriginPath, ParentPath, Path, pDirEnt->d_name);
|
||||
else if (Path)
|
||||
full_path = fmt::format("{}/{}/{}", OriginPath, Path, pDirEnt->d_name);
|
||||
else
|
||||
full_path = StringUtil::StdStringFromFormat("%s/%s", OriginPath, pDirEnt->d_name);
|
||||
full_path = fmt::format("{}/{}", OriginPath, pDirEnt->d_name);
|
||||
|
||||
FILESYSTEM_FIND_DATA outData;
|
||||
outData.Attributes = 0;
|
||||
@@ -1681,15 +1701,23 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
|
||||
{
|
||||
if (Flags & FILESYSTEM_FIND_RECURSIVE)
|
||||
{
|
||||
// recurse into this directory
|
||||
if (ParentPath != nullptr)
|
||||
// check that we're not following an infinite symbolic link loop
|
||||
if (std::string real_recurse_dir = Path::RealPath(full_path);
|
||||
real_recurse_dir.empty() || std::find(visited.begin(), visited.end(), real_recurse_dir) == visited.end())
|
||||
{
|
||||
std::string recursiveDir = StringUtil::StdStringFromFormat("%s/%s", ParentPath, Path);
|
||||
nFiles += RecursiveFindFiles(OriginPath, recursiveDir.c_str(), pDirEnt->d_name, Pattern, Flags, pResults);
|
||||
}
|
||||
else
|
||||
{
|
||||
nFiles += RecursiveFindFiles(OriginPath, Path, pDirEnt->d_name, Pattern, Flags, pResults);
|
||||
if (!real_recurse_dir.empty())
|
||||
visited.push_back(std::move(real_recurse_dir));
|
||||
|
||||
// recurse into this directory
|
||||
if (ParentPath)
|
||||
{
|
||||
const std::string recursive_dir = fmt::format("{}/{}", ParentPath, Path);
|
||||
nFiles += RecursiveFindFiles(OriginPath, recursive_dir.c_str(), pDirEnt->d_name, Pattern, Flags, pResults, visited);
|
||||
}
|
||||
else
|
||||
{
|
||||
nFiles += RecursiveFindFiles(OriginPath, Path, pDirEnt->d_name, Pattern, Flags, pResults, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1721,17 +1749,16 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
|
||||
}
|
||||
|
||||
// add file to list
|
||||
// TODO string formatter, clean this mess..
|
||||
if (!(Flags & FILESYSTEM_FIND_RELATIVE_PATHS))
|
||||
{
|
||||
outData.FileName = std::move(full_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ParentPath != nullptr)
|
||||
outData.FileName = StringUtil::StdStringFromFormat("%s/%s/%s", ParentPath, Path, pDirEnt->d_name);
|
||||
else if (Path != nullptr)
|
||||
outData.FileName = StringUtil::StdStringFromFormat("%s/%s", Path, pDirEnt->d_name);
|
||||
if (ParentPath)
|
||||
outData.FileName = fmt::format("{}/{}/{}", ParentPath, Path, pDirEnt->d_name);
|
||||
else if (Path)
|
||||
outData.FileName = fmt::format("{}/{}", Path, pDirEnt->d_name);
|
||||
else
|
||||
outData.FileName = pDirEnt->d_name;
|
||||
}
|
||||
@@ -1744,18 +1771,27 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
|
||||
return nFiles;
|
||||
}
|
||||
|
||||
bool FileSystem::FindFiles(const char* Path, const char* Pattern, u32 Flags, FindResultsArray* pResults)
|
||||
bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results)
|
||||
{
|
||||
// has a path
|
||||
if (Path[0] == '\0')
|
||||
if (path[0] == '\0')
|
||||
return false;
|
||||
|
||||
// clear result array
|
||||
if (!(Flags & FILESYSTEM_FIND_KEEP_ARRAY))
|
||||
pResults->clear();
|
||||
if (!(flags & FILESYSTEM_FIND_KEEP_ARRAY))
|
||||
results->clear();
|
||||
|
||||
// add self if recursive, we don't want to visit it twice
|
||||
std::vector<std::string> visited;
|
||||
if (flags & FILESYSTEM_FIND_RECURSIVE)
|
||||
{
|
||||
std::string real_path = Path::RealPath(path);
|
||||
if (!real_path.empty())
|
||||
visited.push_back(std::move(real_path));
|
||||
}
|
||||
|
||||
// enter the recursive function
|
||||
return (RecursiveFindFiles(Path, nullptr, nullptr, Pattern, Flags, pResults) > 0);
|
||||
return (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) > 0);
|
||||
}
|
||||
|
||||
bool FileSystem::StatFile(const char* path, struct stat* st)
|
||||
|
||||
@@ -55,6 +55,11 @@ using r128 = __m128i;
|
||||
return _mm_set_epi64x(0, val);
|
||||
}
|
||||
|
||||
[[maybe_unused]] __fi static r128 r128_from_u32_dup(u32 val)
|
||||
{
|
||||
return _mm_set1_epi32(val);
|
||||
}
|
||||
|
||||
[[maybe_unused]] __fi static r128 r128_from_u32x4(u32 lo0, u32 lo1, u32 hi0, u32 hi1)
|
||||
{
|
||||
return _mm_setr_epi32(lo0, lo1, hi0, hi1);
|
||||
@@ -150,6 +155,11 @@ using r128 = uint32x4_t;
|
||||
return vreinterpretq_u32_u64(vcombine_u64(vcreate_u64(val), vcreate_u64(0)));
|
||||
}
|
||||
|
||||
[[maybe_unused]] __fi static r128 r128_from_u32_dup(u32 val)
|
||||
{
|
||||
return vdupq_n_u32(val);
|
||||
}
|
||||
|
||||
[[maybe_unused]] __fi static r128 r128_from_u32x4(u32 lo0, u32 lo1, u32 hi0, u32 hi1)
|
||||
{
|
||||
const u32 values[4] = {lo0, lo1, hi0, hi1};
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include "common/Threading.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <mmsystem.h>
|
||||
#include <process.h>
|
||||
#include <timeapi.h>
|
||||
|
||||
+39
-45
@@ -18,12 +18,15 @@ IF EXIST "%ProgramFiles%\Git\bin\git.exe" SET "GITPATH=%ProgramFiles%\Git\bin"
|
||||
IF EXIST "%ProgramW6432%\Git\bin\git.exe" SET "GITPATH=%ProgramW6432%\Git\bin"
|
||||
IF DEFINED GITPATH SET "PATH=%PATH%;%GITPATH%"
|
||||
|
||||
FOR /F "tokens=1-2" %%i IN ('"git show -s --format=%%%ci HEAD 2> NUL"') do (
|
||||
set REV3=%%i%%j
|
||||
)
|
||||
|
||||
FOR /F %%i IN ('"git describe 2> NUL"') do (
|
||||
set GIT_REV=%%i
|
||||
git describe --tags > NUL 2>NUL
|
||||
if !ERRORLEVEL! EQU 0 (
|
||||
FOR /F %%i IN ('"git describe --tags 2> NUL"') do (
|
||||
set GIT_REV=%%i
|
||||
)
|
||||
) else (
|
||||
FOR /F %%i IN ('"git rev-parse --short HEAD 2> NUL"') do (
|
||||
set GIT_REV=%%i
|
||||
)
|
||||
)
|
||||
|
||||
FOR /F "tokens=* USEBACKQ" %%i IN (`git tag --points-at HEAD`) DO (
|
||||
@@ -34,11 +37,11 @@ FOR /F "tokens=* USEBACKQ" %%i IN (`git rev-parse HEAD`) DO (
|
||||
set GIT_HASH=%%i
|
||||
)
|
||||
|
||||
set REV2=%REV3: =%
|
||||
set REV1=%REV2:-=%
|
||||
set REV=%REV1::=%
|
||||
FOR /F "tokens=* USEBACKQ" %%i IN (`git log -1 "--format=%%cd" "--date=local"`) DO (
|
||||
set GIT_DATE=%%i
|
||||
)
|
||||
|
||||
SET SIGNATURELINE=// H[%GIT_HASH%] T[%GIT_TAG%]
|
||||
SET SIGNATURELINE=// R[%GIT_REV%] H[%GIT_HASH%] T[%GIT_TAG%]
|
||||
SET /P EXISTINGLINE=<"%CD%\svnrev.h"
|
||||
|
||||
IF "%EXISTINGLINE%"=="%SIGNATURELINE%" (
|
||||
@@ -48,45 +51,36 @@ IF "%EXISTINGLINE%"=="%SIGNATURELINE%" (
|
||||
ECHO Updating "%CD%\svnrev.h"...
|
||||
echo %SIGNATURELINE%> "%CD%\svnrev.h"
|
||||
|
||||
git show -s > NUL 2>&1
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Automatic version detection unavailable.
|
||||
echo If you want to have the version string print correctly,
|
||||
echo make sure your Git.exe is in the default installation directory,
|
||||
echo or in your PATH.
|
||||
echo You can safely ignore this message - a dummy string will be printed.
|
||||
echo #define GIT_HASH "%GIT_HASH%" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG "%GIT_TAG%" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_DATE "%GIT_DATE%" >> "%CD%\svnrev.h"
|
||||
|
||||
echo #define SVN_REV_UNKNOWN >> "%CD%\svnrev.h"
|
||||
echo #define SVN_REV 0ll >> "%CD%\svnrev.h"
|
||||
echo #define GIT_REV "" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_HASH "" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG "" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAGGED_COMMIT 0 >> "%CD%\svnrev.h"
|
||||
echo %GIT_TAG%|FINDSTR /R "^v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$" > NUL
|
||||
if !ERRORLEVEL! EQU 0 (
|
||||
echo #define GIT_REV "%GIT_TAG%" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAGGED_COMMIT 1 >> "%CD%\svnrev.h"
|
||||
FOR /F "tokens=1,2,3 delims=v." %%a in ("%GIT_TAG%") DO (
|
||||
echo #define GIT_TAG_HI %%a >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG_MID %%b >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG_LO %%c >> "%CD%\svnrev.h"
|
||||
)
|
||||
) else (
|
||||
:: Support New Tagged Release Model
|
||||
if [%GIT_TAG%] NEQ [] (
|
||||
echo Detected that the current commit is tagged, using that!
|
||||
echo #define SVN_REV %REV%ll >> "%CD%\svnrev.h"
|
||||
echo #define GIT_REV "" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_HASH "%GIT_HASH%" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG "%GIT_TAG%" >> "%CD%\svnrev.h"
|
||||
|
||||
echo %GIT_TAG%|FINDSTR /R "^v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$" > NUL
|
||||
if !ERRORLEVEL! EQU 0 (
|
||||
FOR /F "tokens=1,2,3 delims=v." %%a in ("%GIT_TAG%") DO (
|
||||
echo #define GIT_TAG_HI %%a >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG_MID %%b >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG_LO %%c >> "%CD%\svnrev.h"
|
||||
)
|
||||
:: Local branches
|
||||
echo #define GIT_REV "%GIT_REV%" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAGGED_COMMIT 0 >> "%CD%\svnrev.h"
|
||||
echo %GIT_REV%|FINDSTR /R "^v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]-*" > NUL
|
||||
if !ERRORLEVEL! EQU 0 (
|
||||
FOR /F "tokens=1,2,3 delims=v." %%a in ("%GIT_REV%") DO (
|
||||
echo #define GIT_TAG_HI %%a >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG_MID %%b >> "%CD%\svnrev.h"
|
||||
FOR /F "tokens=1 delims=-" %%d in ("%%c%") DO (
|
||||
echo #define GIT_TAG_LO %%d >> "%CD%\svnrev.h"
|
||||
)
|
||||
)
|
||||
|
||||
echo #define GIT_TAGGED_COMMIT 1 >> "%CD%\svnrev.h"
|
||||
) else (
|
||||
echo #define SVN_REV %REV%ll >> "%CD%\svnrev.h"
|
||||
echo #define GIT_REV "%GIT_REV%" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_HASH "%GIT_HASH%" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG "" >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAGGED_COMMIT 0 >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG_HI 0 >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG_MID 0 >> "%CD%\svnrev.h"
|
||||
echo #define GIT_TAG_LO 0 >> "%CD%\svnrev.h"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
pull_request_title: "translations: Syncing Crowdin translations"
|
||||
commit_message: "[ci skip]"
|
||||
pull_request_title: 'translations: Syncing Crowdin translations'
|
||||
commit_message: '[ci skip]'
|
||||
files:
|
||||
- source: pcsx2-qt/Translations/pcsx2-qt_en.ts
|
||||
translation: '/pcsx2-qt/Translations/pcsx2-qt_%locale%.ts'
|
||||
translation: /pcsx2-qt/Translations/pcsx2-qt_%locale%.ts
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "pcsx2/GameList.h"
|
||||
#include "pcsx2/Host.h"
|
||||
#include "pcsx2/INISettingsInterface.h"
|
||||
#include "pcsx2/ImGui/FullscreenUI.h"
|
||||
#include "pcsx2/ImGui/ImGuiManager.h"
|
||||
#include "pcsx2/Input/InputManager.h"
|
||||
#include "pcsx2/MTGS.h"
|
||||
@@ -391,6 +392,11 @@ void Host::OnCoverDownloaderOpenRequested()
|
||||
// noop
|
||||
}
|
||||
|
||||
void Host::OnCreateMemoryCardOpenRequested()
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
std::optional<u32> InputManager::ConvertHostKeyboardStringToCode(const std::string_view& str)
|
||||
{
|
||||
return std::nullopt;
|
||||
@@ -701,7 +707,7 @@ int main(int argc, char* argv[])
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void Host::VSyncOnCPUThread()
|
||||
void Host::PumpMessagesOnCPUThread()
|
||||
{
|
||||
// update GS thread copy of frame number
|
||||
MTGS::RunOnGSThread([frame_number = GSDumpReplayer::GetFrameNumber()]() { s_dump_frame_number = frame_number; });
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "pcsx2/SysForwardDefs.h"
|
||||
#include "pcsx2/SupportURLs.h"
|
||||
|
||||
#include "AboutDialog.h"
|
||||
#include "QtHost.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "AutoUpdaterDialog.h"
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include "pcsx2/Host.h"
|
||||
#include "pcsx2/SysForwardDefs.h"
|
||||
#include "svnrev.h"
|
||||
|
||||
#include "updater/UpdaterExtractor.h"
|
||||
@@ -16,8 +15,10 @@
|
||||
#include "common/Assertions.h"
|
||||
#include "common/CocoaTools.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/Error.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/HTTPDownloader.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include "cpuinfo.h"
|
||||
@@ -38,12 +39,17 @@
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QProgressDialog>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include <shellapi.h>
|
||||
#endif
|
||||
|
||||
// Interval at which HTTP requests are polled.
|
||||
static constexpr u32 HTTP_POLL_INTERVAL = 10;
|
||||
|
||||
// Logic to detect whether we can use the auto updater.
|
||||
// We use tagged commit, because this gets set on nightly builds.
|
||||
#if (defined(_WIN32) || defined(__linux__) || defined(__APPLE__)) && defined(GIT_TAG_LO)
|
||||
#if (defined(_WIN32) || defined(__linux__) || defined(__APPLE__)) && GIT_TAGGED_COMMIT
|
||||
|
||||
#define AUTO_UPDATER_SUPPORTED 1
|
||||
|
||||
@@ -73,8 +79,13 @@ static constexpr u32 HTTP_POLL_INTERVAL = 10;
|
||||
// Available release channels.
|
||||
static const char* UPDATE_TAGS[] = {"stable", "nightly"};
|
||||
|
||||
// Bit annoying, because PCSX2_isReleaseVersion is a bool, but whatever.
|
||||
#define THIS_RELEASE_TAG (PCSX2_isReleaseVersion ? "stable" : "nightly")
|
||||
// TODO: Make manual releases create this file, and make it contain `#define DEFAULT_UPDATER_CHANNEL "stable"`.
|
||||
#if __has_include("DefaultUpdaterChannel.h")
|
||||
#include "DefaultUpdaterChannel.h"
|
||||
#endif
|
||||
#ifndef DEFAULT_UPDATER_CHANNEL
|
||||
#define DEFAULT_UPDATER_CHANNEL "nightly"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -129,7 +140,7 @@ QStringList AutoUpdaterDialog::getTagList()
|
||||
std::string AutoUpdaterDialog::getDefaultTag()
|
||||
{
|
||||
#ifdef AUTO_UPDATER_SUPPORTED
|
||||
return THIS_RELEASE_TAG;
|
||||
return DEFAULT_UPDATER_CHANNEL;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
@@ -142,15 +153,13 @@ QString AutoUpdaterDialog::getCurrentVersion()
|
||||
|
||||
QString AutoUpdaterDialog::getCurrentVersionDate()
|
||||
{
|
||||
// 20220403235450ll
|
||||
const QDateTime current_build_date(QDateTime::fromString(QStringLiteral("%1").arg(SVN_REV), "yyyyMMddhhmmss"));
|
||||
return current_build_date.toString();
|
||||
return QStringLiteral(GIT_DATE);
|
||||
}
|
||||
|
||||
QString AutoUpdaterDialog::getCurrentUpdateTag() const
|
||||
{
|
||||
#ifdef AUTO_UPDATER_SUPPORTED
|
||||
return QString::fromStdString(Host::GetBaseStringSettingValue("AutoUpdater", "UpdateTag", THIS_RELEASE_TAG));
|
||||
return QString::fromStdString(Host::GetBaseStringSettingValue("AutoUpdater", "UpdateTag", DEFAULT_UPDATER_CHANNEL));
|
||||
#else
|
||||
return QString();
|
||||
#endif
|
||||
@@ -566,70 +575,74 @@ void AutoUpdaterDialog::remindMeLaterClicked()
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
bool AutoUpdaterDialog::doesUpdaterNeedElevation(const std::string& application_dir) const
|
||||
{
|
||||
// Try to create a dummy text file in the PCSX2 updater directory. If it fails, we probably won't have write permission.
|
||||
const std::string dummy_path = Path::Combine(application_dir, "update.txt");
|
||||
auto fp = FileSystem::OpenManagedCFile(dummy_path.c_str(), "wb");
|
||||
if (!fp)
|
||||
return true;
|
||||
|
||||
fp.reset();
|
||||
FileSystem::DeleteFilePath(dummy_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AutoUpdaterDialog::processUpdate(const std::vector<u8>& data, QProgressDialog&)
|
||||
{
|
||||
const QString update_directory = QCoreApplication::applicationDirPath();
|
||||
const QString update_zip_path = QStringLiteral("%1" FS_OSPATH_SEPARATOR_STR "%2").arg(update_directory).arg(UPDATER_ARCHIVE_NAME);
|
||||
const QString updater_path = QStringLiteral("%1" FS_OSPATH_SEPARATOR_STR "%2").arg(update_directory).arg(UPDATER_EXECUTABLE);
|
||||
const std::string& application_dir = EmuFolders::AppRoot;
|
||||
const std::string update_zip_path = Path::Combine(EmuFolders::DataRoot, UPDATER_ARCHIVE_NAME);
|
||||
const std::string updater_path = Path::Combine(EmuFolders::DataRoot, UPDATER_EXECUTABLE);
|
||||
|
||||
Q_ASSERT(!update_zip_path.isEmpty() && !updater_path.isEmpty() && !update_directory.isEmpty());
|
||||
if ((QFile::exists(update_zip_path) && !QFile::remove(update_zip_path)) ||
|
||||
(QFile::exists(updater_path) && !QFile::remove(updater_path)))
|
||||
if ((FileSystem::FileExists(update_zip_path.c_str()) && !FileSystem::DeleteFilePath(update_zip_path.c_str())))
|
||||
{
|
||||
reportError("Removing existing update zip/updater failed");
|
||||
reportError("Removing existing update zip failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FileSystem::WriteBinaryFile(update_zip_path.c_str(), data.data(), data.size()))
|
||||
{
|
||||
QFile update_zip_file(update_zip_path);
|
||||
if (!update_zip_file.open(QIODevice::WriteOnly) ||
|
||||
update_zip_file.write(reinterpret_cast<const char*>(data.data()), static_cast<qint64>(data.size())) != static_cast<qint64>(data.size()))
|
||||
{
|
||||
reportError("Writing update zip to '%s' failed", update_zip_path.toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
update_zip_file.close();
|
||||
reportError("Writing update zip to '%s' failed", update_zip_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string updater_extract_error;
|
||||
if (!ExtractUpdater(update_zip_path.toUtf8().constData(), updater_path.toUtf8().constData(), &updater_extract_error))
|
||||
if (!ExtractUpdater(update_zip_path.c_str(), updater_path.c_str(), &updater_extract_error))
|
||||
{
|
||||
reportError("Extracting updater failed: %s", updater_extract_error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!doUpdate(update_zip_path, updater_path, update_directory))
|
||||
{
|
||||
reportError("Launching updater failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return doUpdate(application_dir, update_zip_path, updater_path);
|
||||
}
|
||||
|
||||
bool AutoUpdaterDialog::doUpdate(const QString& zip_path, const QString& updater_path, const QString& destination_path)
|
||||
bool AutoUpdaterDialog::doUpdate(const std::string& application_dir, const std::string& zip_path, const std::string& updater_path)
|
||||
{
|
||||
const QString program_path = QCoreApplication::applicationFilePath();
|
||||
if (program_path.isEmpty())
|
||||
const std::string program_path = QDir::toNativeSeparators(QCoreApplication::applicationFilePath()).toStdString();
|
||||
if (program_path.empty())
|
||||
{
|
||||
reportError("Failed to get current application path");
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList arguments;
|
||||
arguments << QString::number(QCoreApplication::applicationPid());
|
||||
arguments << destination_path;
|
||||
arguments << zip_path;
|
||||
arguments << program_path;
|
||||
const std::wstring wupdater_path = StringUtil::UTF8StringToWideString(updater_path);
|
||||
const std::wstring wapplication_dir = StringUtil::UTF8StringToWideString(application_dir);
|
||||
const std::wstring arguments = StringUtil::UTF8StringToWideString(fmt::format("{} \"{}\" \"{}\" \"{}\"",
|
||||
QCoreApplication::applicationPid(), application_dir, zip_path, program_path));
|
||||
|
||||
// this will leak, but not sure how else to handle it...
|
||||
QProcess* updater_process = new QProcess();
|
||||
updater_process->setProgram(updater_path);
|
||||
updater_process->setArguments(arguments);
|
||||
updater_process->start(QIODevice::NotOpen);
|
||||
if (!updater_process->waitForStarted())
|
||||
const bool needs_elevation = doesUpdaterNeedElevation(application_dir);
|
||||
|
||||
SHELLEXECUTEINFOW sei = {};
|
||||
sei.cbSize = sizeof(sei);
|
||||
sei.lpVerb = needs_elevation ? L"runas" : nullptr; // needed to trigger elevation
|
||||
sei.lpFile = wupdater_path.c_str();
|
||||
sei.lpParameters = arguments.c_str();
|
||||
sei.lpDirectory = wapplication_dir.c_str();
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
if (!ShellExecuteExW(&sei))
|
||||
{
|
||||
reportError("Failed to start updater");
|
||||
reportError("Failed to start %s: %s", needs_elevation ? "elevated updater" : "updater",
|
||||
Error::CreateWin32(GetLastError()).GetDescription().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -638,7 +651,19 @@ bool AutoUpdaterDialog::doUpdate(const QString& zip_path, const QString& updater
|
||||
|
||||
void AutoUpdaterDialog::cleanupAfterUpdate()
|
||||
{
|
||||
// Nothing to do on Windows for now, the updater stub cleans everything up.
|
||||
// If we weren't portable, then updater executable gets left in the application directory.
|
||||
if (EmuFolders::AppRoot == EmuFolders::DataRoot)
|
||||
return;
|
||||
|
||||
const std::string updater_path = Path::Combine(EmuFolders::DataRoot, UPDATER_EXECUTABLE);
|
||||
if (!FileSystem::FileExists(updater_path.c_str()))
|
||||
return;
|
||||
|
||||
if (!FileSystem::DeleteFilePath(updater_path.c_str()))
|
||||
{
|
||||
QMessageBox::critical(nullptr, tr("Updater Error"), tr("Failed to remove updater exe after update."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#pragma once
|
||||
@@ -60,7 +60,8 @@ private:
|
||||
|
||||
bool processUpdate(const std::vector<u8>& data, QProgressDialog& progress);
|
||||
#if defined(_WIN32)
|
||||
bool doUpdate(const QString& zip_path, const QString& updater_path, const QString& destination_path);
|
||||
bool doesUpdaterNeedElevation(const std::string& application_dir) const;
|
||||
bool doUpdate(const std::string& application_dir, const std::string& zip_path, const std::string& updater_path);
|
||||
#endif
|
||||
|
||||
Ui::AutoUpdaterDialog m_ui;
|
||||
|
||||
@@ -75,6 +75,7 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Settings/ControllerGlobalSettingsWidget.ui
|
||||
Settings/ControllerMacroEditWidget.ui
|
||||
Settings/ControllerMacroWidget.ui
|
||||
Settings/ControllerMappingSettingsDialog.ui
|
||||
Settings/ControllerMouseSettingsDialog.ui
|
||||
Settings/ControllerSettingsWindow.cpp
|
||||
Settings/ControllerSettingsWindow.h
|
||||
@@ -149,6 +150,8 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Debugger/CpuWidget.cpp
|
||||
Debugger/CpuWidget.h
|
||||
Debugger/CpuWidget.ui
|
||||
Debugger/DebuggerSettingsManager.cpp
|
||||
Debugger/DebuggerSettingsManager.h
|
||||
Debugger/DebuggerWindow.cpp
|
||||
Debugger/DebuggerWindow.h
|
||||
Debugger/DebuggerWindow.ui
|
||||
@@ -247,4 +250,5 @@ if(WIN32)
|
||||
)
|
||||
endif()
|
||||
|
||||
fixup_file_properties(pcsx2-qt)
|
||||
setup_main_executable(pcsx2-qt)
|
||||
|
||||
+104
-144
@@ -8,6 +8,7 @@
|
||||
#include "Models/BreakpointModel.h"
|
||||
#include "Models/ThreadModel.h"
|
||||
#include "Models/SavedAddressesModel.h"
|
||||
#include "Debugger/DebuggerSettingsManager.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
@@ -45,6 +46,15 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
|
||||
m_ui.setupUi(this);
|
||||
|
||||
connect(g_emu_thread, &EmuThread::onVMPaused, this, &CpuWidget::onVMPaused);
|
||||
connect(g_emu_thread, &EmuThread::onGameChanged, [this](const QString& title) {
|
||||
if (title.isEmpty())
|
||||
return;
|
||||
// Don't overwrite users BPs/Saved Addresses unless they have a clean state.
|
||||
if (m_bpModel.rowCount() == 0)
|
||||
DebuggerSettingsManager::loadGameSettings(&m_bpModel);
|
||||
if (m_savedAddressesModel.rowCount() == 0)
|
||||
DebuggerSettingsManager::loadGameSettings(&m_savedAddressesModel);
|
||||
});
|
||||
|
||||
connect(m_ui.registerWidget, &RegisterWidget::gotoInDisasm, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddress);
|
||||
connect(m_ui.memoryviewWidget, &MemoryViewWidget::gotoInDisasm, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddress);
|
||||
@@ -143,9 +153,12 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
|
||||
m_ui.savedAddressesList->horizontalHeader()->setSectionResizeMode(i++, mode);
|
||||
}
|
||||
QTableView* savedAddressesTableView = m_ui.savedAddressesList;
|
||||
connect(m_ui.savedAddressesList->model(), &QAbstractItemModel::dataChanged, [savedAddressesTableView](const QModelIndex& topLeft) {
|
||||
connect(m_ui.savedAddressesList->model(), &QAbstractItemModel::dataChanged, [savedAddressesTableView](const QModelIndex& topLeft) {
|
||||
savedAddressesTableView->resizeColumnToContents(topLeft.column());
|
||||
});
|
||||
|
||||
DebuggerSettingsManager::loadGameSettings(&m_bpModel);
|
||||
DebuggerSettingsManager::loadGameSettings(&m_savedAddressesModel);
|
||||
}
|
||||
|
||||
CpuWidget::~CpuWidget() = default;
|
||||
@@ -301,46 +314,63 @@ void CpuWidget::onBPListDoubleClicked(const QModelIndex& index)
|
||||
|
||||
void CpuWidget::onBPListContextMenu(QPoint pos)
|
||||
{
|
||||
if (!m_cpu.isAlive())
|
||||
return;
|
||||
|
||||
QMenu* contextMenu = new QMenu(tr("Breakpoint List Context Menu"), m_ui.breakpointList);
|
||||
|
||||
QAction* newAction = new QAction(tr("New"), m_ui.breakpointList);
|
||||
connect(newAction, &QAction::triggered, this, &CpuWidget::contextBPListNew);
|
||||
contextMenu->addAction(newAction);
|
||||
|
||||
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
|
||||
|
||||
if (selModel->hasSelection())
|
||||
if (m_cpu.isAlive())
|
||||
{
|
||||
QAction* editAction = new QAction(tr("Edit"), m_ui.breakpointList);
|
||||
connect(editAction, &QAction::triggered, this, &CpuWidget::contextBPListEdit);
|
||||
contextMenu->addAction(editAction);
|
||||
|
||||
if (selModel->selectedIndexes().count() == 1)
|
||||
QAction* newAction = new QAction(tr("New"), m_ui.breakpointList);
|
||||
connect(newAction, &QAction::triggered, this, &CpuWidget::contextBPListNew);
|
||||
contextMenu->addAction(newAction);
|
||||
|
||||
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
|
||||
|
||||
if (selModel->hasSelection())
|
||||
{
|
||||
QAction* copyAction = new QAction(tr("Copy"), m_ui.breakpointList);
|
||||
connect(copyAction, &QAction::triggered, this, &CpuWidget::contextBPListCopy);
|
||||
contextMenu->addAction(copyAction);
|
||||
}
|
||||
QAction* editAction = new QAction(tr("Edit"), m_ui.breakpointList);
|
||||
connect(editAction, &QAction::triggered, this, &CpuWidget::contextBPListEdit);
|
||||
contextMenu->addAction(editAction);
|
||||
|
||||
QAction* deleteAction = new QAction(tr("Delete"), m_ui.breakpointList);
|
||||
connect(deleteAction, &QAction::triggered, this, &CpuWidget::contextBPListDelete);
|
||||
contextMenu->addAction(deleteAction);
|
||||
if (selModel->selectedIndexes().count() == 1)
|
||||
{
|
||||
QAction* copyAction = new QAction(tr("Copy"), m_ui.breakpointList);
|
||||
connect(copyAction, &QAction::triggered, this, &CpuWidget::contextBPListCopy);
|
||||
contextMenu->addAction(copyAction);
|
||||
}
|
||||
|
||||
QAction* deleteAction = new QAction(tr("Delete"), m_ui.breakpointList);
|
||||
connect(deleteAction, &QAction::triggered, this, &CpuWidget::contextBPListDelete);
|
||||
contextMenu->addAction(deleteAction);
|
||||
}
|
||||
}
|
||||
|
||||
contextMenu->addSeparator();
|
||||
QAction* actionExport = new QAction(tr("Copy all as CSV"), m_ui.breakpointList);
|
||||
connect(actionExport, &QAction::triggered, [this]() {
|
||||
// It's important to use the Export Role here to allow pasting to be translation agnostic
|
||||
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.breakpointList->model(), BreakpointModel::ExportRole, true));
|
||||
});
|
||||
contextMenu->addAction(actionExport);
|
||||
if (m_bpModel.rowCount() > 0)
|
||||
{
|
||||
QAction* actionExport = new QAction(tr("Copy all as CSV"), m_ui.breakpointList);
|
||||
connect(actionExport, &QAction::triggered, [this]() {
|
||||
// It's important to use the Export Role here to allow pasting to be translation agnostic
|
||||
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.breakpointList->model(), BreakpointModel::ExportRole, true));
|
||||
});
|
||||
contextMenu->addAction(actionExport);
|
||||
}
|
||||
|
||||
QAction* actionImport = new QAction(tr("Paste from CSV"), m_ui.breakpointList);
|
||||
connect(actionImport, &QAction::triggered, this, &CpuWidget::contextBPListPasteCSV);
|
||||
contextMenu->addAction(actionImport);
|
||||
if (m_cpu.isAlive())
|
||||
{
|
||||
QAction* actionImport = new QAction(tr("Paste from CSV"), m_ui.breakpointList);
|
||||
connect(actionImport, &QAction::triggered, this, &CpuWidget::contextBPListPasteCSV);
|
||||
contextMenu->addAction(actionImport);
|
||||
|
||||
QAction* actionLoad = new QAction(tr("Load from Settings"), m_ui.breakpointList);
|
||||
connect(actionLoad, &QAction::triggered, [this]() {
|
||||
m_bpModel.clear();
|
||||
DebuggerSettingsManager::loadGameSettings(&m_bpModel);
|
||||
});
|
||||
contextMenu->addAction(actionLoad);
|
||||
|
||||
QAction* actionSave = new QAction(tr("Save to Settings"), m_ui.breakpointList);
|
||||
connect(actionSave, &QAction::triggered, this, &CpuWidget::saveBreakpointsToDebuggerSettings);
|
||||
contextMenu->addAction(actionSave);
|
||||
}
|
||||
|
||||
contextMenu->popup(m_ui.breakpointList->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
@@ -407,7 +437,7 @@ void CpuWidget::contextBPListPasteCSV()
|
||||
// In order to handle text with commas in them we must wrap values in quotes to mark
|
||||
// where a value starts and end so that text commas aren't identified as delimiters.
|
||||
// So matches each quote pair, parse it out, and removes the quotes to get the value.
|
||||
QRegularExpression eachQuotePair(R"("([^"]|\\.)*")");
|
||||
QRegularExpression eachQuotePair(R"("([^"]|\\.)*")");
|
||||
QRegularExpressionMatchIterator it = eachQuotePair.globalMatch(line);
|
||||
while (it.hasNext())
|
||||
{
|
||||
@@ -415,98 +445,7 @@ void CpuWidget::contextBPListPasteCSV()
|
||||
QString matchedValue = match.captured(0);
|
||||
fields << matchedValue.mid(1, matchedValue.length() - 2);
|
||||
}
|
||||
|
||||
if (fields.size() != BreakpointModel::BreakpointColumns::COLUMN_COUNT)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Invalid number of columns, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
const int type = fields[BreakpointModel::BreakpointColumns::TYPE].toUInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse type '%s', skipping", fields[BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is how we differentiate between breakpoints and memchecks
|
||||
if (type == MEMCHECK_INVALID)
|
||||
{
|
||||
BreakPoint bp;
|
||||
|
||||
// Address
|
||||
bp.addr = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Condition
|
||||
if (!fields[BreakpointModel::BreakpointColumns::CONDITION].isEmpty())
|
||||
{
|
||||
PostfixExpression expr;
|
||||
bp.hasCond = true;
|
||||
bp.cond.debug = &m_cpu;
|
||||
|
||||
if (!m_cpu.initExpression(fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), expr))
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse cond '%s', skipping", fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
bp.cond.expression = expr;
|
||||
strncpy(&bp.cond.expressionString[0], fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), sizeof(bp.cond.expressionString));
|
||||
}
|
||||
|
||||
// Enabled
|
||||
bp.enabled = fields[BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse enable flag '%s', skipping", fields[BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
m_bpModel.insertBreakpointRows(0, 1, {bp});
|
||||
}
|
||||
else
|
||||
{
|
||||
MemCheck mc;
|
||||
// Mode
|
||||
if (type >= MEMCHECK_INVALID)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse cond type '%s', skipping", fields [BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
mc.cond = static_cast<MemCheckCondition>(type);
|
||||
|
||||
// Address
|
||||
mc.start = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Size
|
||||
mc.end = fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUInt(&ok) + mc.start;
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse length '%s', skipping", fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Result
|
||||
const int result = fields [BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse result flag '%s', skipping", fields [BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
mc.result = static_cast<MemCheckResult>(result);
|
||||
|
||||
m_bpModel.insertBreakpointRows(0, 1, {mc});
|
||||
}
|
||||
m_bpModel.loadBreakpointFromFieldList(fields);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -561,7 +500,19 @@ void CpuWidget::onSavedAddressesListContextMenu(QPoint pos)
|
||||
connect(actionImportCSV, &QAction::triggered, this, &CpuWidget::contextSavedAddressesListPasteCSV);
|
||||
contextMenu->addAction(actionImportCSV);
|
||||
|
||||
contextMenu->popup(m_ui.savedAddressesList->viewport()->mapToGlobal(pos));
|
||||
if (m_cpu.isAlive())
|
||||
{
|
||||
QAction* actionLoad = new QAction(tr("Load from Settings"), m_ui.savedAddressesList);
|
||||
connect(actionLoad, &QAction::triggered, [this]() {
|
||||
m_savedAddressesModel.clear();
|
||||
DebuggerSettingsManager::loadGameSettings(&m_savedAddressesModel);
|
||||
});
|
||||
contextMenu->addAction(actionLoad);
|
||||
|
||||
QAction* actionSave = new QAction(tr("Save to Settings"), m_ui.savedAddressesList);
|
||||
connect(actionSave, &QAction::triggered, this, &CpuWidget::saveSavedAddressesToDebuggerSettings);
|
||||
contextMenu->addAction(actionSave);
|
||||
}
|
||||
|
||||
if (isIndexValid)
|
||||
{
|
||||
@@ -571,6 +522,8 @@ void CpuWidget::onSavedAddressesListContextMenu(QPoint pos)
|
||||
});
|
||||
contextMenu->addAction(deleteAction);
|
||||
}
|
||||
|
||||
contextMenu->popup(m_ui.savedAddressesList->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void CpuWidget::contextSavedAddressesListPasteCSV()
|
||||
@@ -594,24 +547,7 @@ void CpuWidget::contextSavedAddressesListPasteCSV()
|
||||
fields << matchedValue.mid(1, matchedValue.length() - 2);
|
||||
}
|
||||
|
||||
if (fields.size() != SavedAddressesModel::HeaderColumns::COLUMN_COUNT)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Invalid number of columns, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
const u32 address = fields[SavedAddressesModel::HeaderColumns::ADDRESS].toUInt(&ok, 16);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse address '%s', skipping", fields[SavedAddressesModel::HeaderColumns::ADDRESS].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString label = fields[SavedAddressesModel::HeaderColumns::LABEL];
|
||||
const QString description = fields[SavedAddressesModel::HeaderColumns::DESCRIPTION];
|
||||
const SavedAddressesModel::SavedAddress importedAddress = {address, label, description};
|
||||
m_savedAddressesModel.addRow(importedAddress);
|
||||
m_savedAddressesModel.loadSavedAddressFromFieldList(fields);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,6 +592,17 @@ void CpuWidget::contextRemoveSearchResult()
|
||||
delete rowToRemove;
|
||||
}
|
||||
|
||||
void CpuWidget::contextCopySearchResultAddress()
|
||||
{
|
||||
if (!m_ui.listSearchResults->selectionModel()->hasSelection())
|
||||
return;
|
||||
|
||||
const u32 selectedResultIndex = m_ui.listSearchResults->row(m_ui.listSearchResults->selectedItems().first());
|
||||
const u32 rowAddress = m_ui.listSearchResults->item(selectedResultIndex)->data(Qt::UserRole).toUInt();
|
||||
const QString addressString = FilledQStringFromValue(rowAddress, 16);
|
||||
QApplication::clipboard()->setText(addressString);
|
||||
}
|
||||
|
||||
void CpuWidget::updateFunctionList(bool whenEmpty)
|
||||
{
|
||||
if (!m_cpu.isAlive())
|
||||
@@ -958,6 +905,10 @@ void CpuWidget::onListSearchResultsContextMenu(QPoint pos)
|
||||
|
||||
if (selModel->hasSelection())
|
||||
{
|
||||
QAction* copyAddressAction = new QAction(tr("Copy Address"), m_ui.listSearchResults);
|
||||
connect(copyAddressAction, &QAction::triggered, this, &CpuWidget::contextCopySearchResultAddress);
|
||||
contextMenu->addAction(copyAddressAction);
|
||||
|
||||
QAction* goToDisassemblyAction = new QAction(tr("Go to in Disassembly"), m_ui.listSearchResults);
|
||||
connect(goToDisassemblyAction, &QAction::triggered, this, &CpuWidget::contextSearchResultGoToDisassembly);
|
||||
contextMenu->addAction(goToDisassemblyAction);
|
||||
@@ -1392,3 +1343,12 @@ void CpuWidget::loadSearchResults()
|
||||
}
|
||||
}
|
||||
|
||||
void CpuWidget::saveBreakpointsToDebuggerSettings()
|
||||
{
|
||||
DebuggerSettingsManager::saveGameSettings(&m_bpModel);
|
||||
}
|
||||
|
||||
void CpuWidget::saveSavedAddressesToDebuggerSettings()
|
||||
{
|
||||
DebuggerSettingsManager::saveGameSettings(&m_savedAddressesModel);
|
||||
}
|
||||
|
||||
@@ -116,8 +116,12 @@ public slots:
|
||||
void loadSearchResults();
|
||||
void contextSearchResultGoToDisassembly();
|
||||
void contextRemoveSearchResult();
|
||||
void contextCopySearchResultAddress();
|
||||
void onListSearchResultsContextMenu(QPoint pos);
|
||||
|
||||
void saveBreakpointsToDebuggerSettings();
|
||||
void saveSavedAddressesToDebuggerSettings();
|
||||
|
||||
private:
|
||||
std::vector<QTableWidget*> m_registerTableViews;
|
||||
std::vector<u32> m_searchResults;
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "DebuggerSettingsManager.h"
|
||||
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include "common/Console.h"
|
||||
#include "fmt/core.h"
|
||||
#include "VMManager.h"
|
||||
#include "Models/BreakpointModel.h"
|
||||
|
||||
std::mutex DebuggerSettingsManager::writeLock;
|
||||
const QString DebuggerSettingsManager::settingsFileVersion = "0.00";
|
||||
|
||||
QJsonObject DebuggerSettingsManager::loadGameSettingsJSON() {
|
||||
std::string path = VMManager::GetDebuggerSettingsFilePathForCurrentGame();
|
||||
QFile file(QString::fromStdString(path));
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
Console.WriteLnFmt("Debugger Settings Manager: No Debugger Settings file found for game at: '{}'", path);
|
||||
return QJsonObject();
|
||||
}
|
||||
QByteArray fileContent = file.readAll();
|
||||
file.close();
|
||||
|
||||
const QJsonDocument jsonDoc(QJsonDocument::fromJson(fileContent));
|
||||
if (jsonDoc.isNull() || !jsonDoc.isObject())
|
||||
{
|
||||
Console.WriteLnFmt("Debugger Settings Manager: Failed to load contents of settings file for file at: '{}'", path);
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
return jsonDoc.object();
|
||||
}
|
||||
|
||||
void DebuggerSettingsManager::writeJSONToPath(std::string path, QJsonDocument jsonDocument)
|
||||
{
|
||||
QFile file(QString::fromStdString(path));
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
Console.WriteLnFmt("Debugger Settings Manager: Failed to write Debugger Settings file to path: '{}'", path);
|
||||
return;
|
||||
}
|
||||
file.write(jsonDocument.toJson(QJsonDocument::Indented));
|
||||
file.close();
|
||||
}
|
||||
|
||||
void DebuggerSettingsManager::loadGameSettings(BreakpointModel* bpModel)
|
||||
{
|
||||
const std::string path = VMManager::GetDebuggerSettingsFilePathForCurrentGame();
|
||||
if (path.empty())
|
||||
return;
|
||||
|
||||
const QJsonValue breakpointsValue = loadGameSettingsJSON().value("Breakpoints");
|
||||
const QString valueToLoad = breakpointsValue.toString();
|
||||
if (breakpointsValue.isUndefined() || !breakpointsValue.isArray())
|
||||
{
|
||||
Console.WriteLnFmt("Debugger Settings Manager: Failed to read Breakpoints array from settings file: '{}'", path);
|
||||
return;
|
||||
}
|
||||
|
||||
const QJsonArray breakpointsArray = breakpointsValue.toArray();
|
||||
for (u32 row = 0; row < breakpointsArray.size(); row++)
|
||||
{
|
||||
const QJsonValue rowValue = breakpointsArray.at(row);
|
||||
if (rowValue.isUndefined() || !rowValue.isObject())
|
||||
{
|
||||
Console.WriteLn("Debugger Settings Manager: Failed to load invalid Breakpoint object.");
|
||||
continue;
|
||||
}
|
||||
const QJsonObject rowObject = rowValue.toObject();
|
||||
|
||||
QStringList fields;
|
||||
u32 col = 0;
|
||||
for (auto iter = rowObject.begin(); iter != rowObject.end(); iter++, col++)
|
||||
{
|
||||
QString headerColKey = bpModel->headerData(col, Qt::Horizontal, Qt::UserRole).toString();
|
||||
fields << rowObject.value(headerColKey).toString();
|
||||
}
|
||||
bpModel->loadBreakpointFromFieldList(fields);
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerSettingsManager::loadGameSettings(SavedAddressesModel* savedAddressesModel)
|
||||
{
|
||||
const std::string path = VMManager::GetDebuggerSettingsFilePathForCurrentGame();
|
||||
if (path.empty())
|
||||
return;
|
||||
|
||||
const QJsonValue savedAddressesValue = loadGameSettingsJSON().value("SavedAddresses");
|
||||
QString valueToLoad = savedAddressesValue.toString();
|
||||
if (savedAddressesValue.isUndefined() || !savedAddressesValue.isArray())
|
||||
{
|
||||
Console.WriteLnFmt("Debugger Settings Manager: Failed to read Saved Addresses array from settings file: '{}'", path);
|
||||
return;
|
||||
}
|
||||
|
||||
const QJsonArray breakpointsArray = savedAddressesValue.toArray();
|
||||
|
||||
for (u32 row = 0; row < breakpointsArray.size(); row++)
|
||||
{
|
||||
const QJsonValue rowValue = breakpointsArray.at(row);
|
||||
if (rowValue.isUndefined() || !rowValue.isObject())
|
||||
{
|
||||
Console.WriteLn("Debugger Settings Manager: Failed to load invalid Breakpoint object.");
|
||||
continue;
|
||||
}
|
||||
const QJsonObject rowObject = rowValue.toObject();
|
||||
QStringList fields;
|
||||
u32 col = 0;
|
||||
for (auto iter = rowObject.begin(); iter != rowObject.end(); iter++, col++)
|
||||
{
|
||||
QString headerColKey = savedAddressesModel->headerData(col, Qt::Horizontal, Qt::UserRole).toString();
|
||||
fields << rowObject.value(headerColKey).toString();
|
||||
}
|
||||
savedAddressesModel->loadSavedAddressFromFieldList(fields);
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerSettingsManager::saveGameSettings(BreakpointModel* bpModel)
|
||||
{
|
||||
saveGameSettings(bpModel, "Breakpoints", BreakpointModel::ExportRole);
|
||||
}
|
||||
|
||||
void DebuggerSettingsManager::saveGameSettings(SavedAddressesModel* savedAddressesModel)
|
||||
{
|
||||
saveGameSettings(savedAddressesModel, "SavedAddresses", Qt::DisplayRole);
|
||||
}
|
||||
|
||||
void DebuggerSettingsManager::saveGameSettings(QAbstractTableModel* abstractTableModel, QString settingsKey, u32 role)
|
||||
{
|
||||
const std::string path = VMManager::GetDebuggerSettingsFilePathForCurrentGame();
|
||||
if (path.empty())
|
||||
return;
|
||||
|
||||
const std::lock_guard<std::mutex> lock(writeLock);
|
||||
QJsonObject loadedSettings = loadGameSettingsJSON();
|
||||
QJsonArray rowsArray;
|
||||
QStringList keys;
|
||||
for (int col = 0; col < abstractTableModel->columnCount(); ++col)
|
||||
{
|
||||
keys << abstractTableModel->headerData(col, Qt::Horizontal, Qt::UserRole).toString();
|
||||
}
|
||||
|
||||
for (int row = 0; row < abstractTableModel->rowCount(); row++)
|
||||
{
|
||||
QJsonObject rowObject;
|
||||
for (int col = 0; col < abstractTableModel->columnCount(); col++)
|
||||
{
|
||||
const QModelIndex index = abstractTableModel->index(row, col);
|
||||
const QString data = abstractTableModel->data(index, role).toString();
|
||||
rowObject.insert(keys[col], QJsonValue::fromVariant(data));
|
||||
}
|
||||
rowsArray.append(rowObject);
|
||||
}
|
||||
loadedSettings.insert(settingsKey, rowsArray);
|
||||
loadedSettings.insert("Version", settingsFileVersion);
|
||||
QJsonDocument doc(loadedSettings);
|
||||
writeJSONToPath(path, doc);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#pragma once
|
||||
#include <QtWidgets/QDialog>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "Models/BreakpointModel.h"
|
||||
#include "Models/SavedAddressesModel.h"
|
||||
|
||||
class DebuggerSettingsManager final
|
||||
{
|
||||
public:
|
||||
DebuggerSettingsManager(QWidget* parent = nullptr);
|
||||
~DebuggerSettingsManager();
|
||||
|
||||
static void loadGameSettings(BreakpointModel* bpModel);
|
||||
static void loadGameSettings(SavedAddressesModel* savedAddressesModel);
|
||||
static void saveGameSettings(BreakpointModel* bpModel);
|
||||
static void saveGameSettings(SavedAddressesModel* savedAddressesModel);
|
||||
static void saveGameSettings(QAbstractTableModel* abstractTableModel, QString settingsKey, u32 role);
|
||||
|
||||
private:
|
||||
static std::mutex writeLock;
|
||||
static void writeJSONToPath(std::string path, QJsonDocument jsonDocument);
|
||||
static QJsonObject loadGameSettingsJSON();
|
||||
const static QString settingsFileVersion;
|
||||
};
|
||||
@@ -95,6 +95,9 @@
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOnTop">
|
||||
<property name="icon">
|
||||
<iconset theme="pin-filled"/>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
#include "DebugTools/DisassemblyManager.h"
|
||||
#include "common/Console.h"
|
||||
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
@@ -226,6 +227,28 @@ QVariant BreakpointModel::headerData(int section, Qt::Orientation orientation, i
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
if (role == Qt::UserRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case BreakpointColumns::TYPE:
|
||||
return "TYPE";
|
||||
case BreakpointColumns::OFFSET:
|
||||
return "OFFSET";
|
||||
case BreakpointColumns::SIZE_LABEL:
|
||||
return "SIZE / LABEL";
|
||||
case BreakpointColumns::OPCODE:
|
||||
return "INSTRUCTION";
|
||||
case BreakpointColumns::CONDITION:
|
||||
return "CONDITION";
|
||||
case BreakpointColumns::HITS:
|
||||
return "HITS";
|
||||
case BreakpointColumns::ENABLED:
|
||||
return "X";
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
@@ -402,3 +425,106 @@ void BreakpointModel::refreshData()
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void BreakpointModel::loadBreakpointFromFieldList(QStringList fields)
|
||||
{
|
||||
bool ok;
|
||||
if (fields.size() != BreakpointModel::BreakpointColumns::COLUMN_COUNT)
|
||||
{
|
||||
Console.WriteLn("Debugger Breakpoint Model: Invalid number of columns, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
const int type = fields[BreakpointModel::BreakpointColumns::TYPE].toUInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger Breakpoint Model: Failed to parse type '%s', skipping", fields[BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
|
||||
return;
|
||||
}
|
||||
|
||||
// This is how we differentiate between breakpoints and memchecks
|
||||
if (type == MEMCHECK_INVALID)
|
||||
{
|
||||
BreakPoint bp;
|
||||
|
||||
// Address
|
||||
bp.addr = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger Breakpoint Model: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData());
|
||||
return;
|
||||
}
|
||||
|
||||
// Condition
|
||||
if (!fields[BreakpointModel::BreakpointColumns::CONDITION].isEmpty())
|
||||
{
|
||||
PostfixExpression expr;
|
||||
bp.hasCond = true;
|
||||
bp.cond.debug = &m_cpu;
|
||||
|
||||
if (!m_cpu.initExpression(fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), expr))
|
||||
{
|
||||
Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond '%s', skipping", fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData());
|
||||
return;
|
||||
}
|
||||
bp.cond.expression = expr;
|
||||
strncpy(&bp.cond.expressionString[0], fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), sizeof(bp.cond.expressionString));
|
||||
}
|
||||
|
||||
// Enabled
|
||||
bp.enabled = fields[BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger Breakpoint Model: Failed to parse enable flag '%s', skipping", fields[BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData());
|
||||
return;
|
||||
}
|
||||
|
||||
insertBreakpointRows(0, 1, {bp});
|
||||
}
|
||||
else
|
||||
{
|
||||
MemCheck mc;
|
||||
// Mode
|
||||
if (type >= MEMCHECK_INVALID)
|
||||
{
|
||||
Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond type '%s', skipping", fields[BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
|
||||
return;
|
||||
}
|
||||
mc.cond = static_cast<MemCheckCondition>(type);
|
||||
|
||||
// Address
|
||||
QString test = fields[BreakpointModel::BreakpointColumns::OFFSET];
|
||||
mc.start = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger Breakpoint Model: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData());
|
||||
return;
|
||||
}
|
||||
|
||||
// Size
|
||||
mc.end = fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUInt(&ok) + mc.start;
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger Breakpoint Model: Failed to parse length '%s', skipping", fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUtf8().constData());
|
||||
return;
|
||||
}
|
||||
|
||||
// Result
|
||||
const int result = fields[BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger Breakpoint Model: Failed to parse result flag '%s', skipping", fields[BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData());
|
||||
return;
|
||||
}
|
||||
mc.result = static_cast<MemCheckResult>(result);
|
||||
|
||||
insertBreakpointRows(0, 1, {mc});
|
||||
}
|
||||
}
|
||||
|
||||
void BreakpointModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
m_breakpoints.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
@@ -55,10 +55,12 @@ public:
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
|
||||
bool removeRows(int row, int count, const QModelIndex& index = QModelIndex()) override;
|
||||
bool insertBreakpointRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index = QModelIndex());
|
||||
void loadBreakpointFromFieldList(QStringList breakpointFields);
|
||||
|
||||
BreakpointMemcheck at(int row) const { return m_breakpoints.at(row); };
|
||||
|
||||
void refreshData();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
DebugInterface& m_cpu;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "SavedAddressesModel.h"
|
||||
|
||||
#include "common/Console.h"
|
||||
|
||||
SavedAddressesModel::SavedAddressesModel(DebugInterface& cpu, QObject* parent)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_cpu(cpu)
|
||||
@@ -96,20 +98,38 @@ bool SavedAddressesModel::setData(const QModelIndex& index, const QVariant& valu
|
||||
|
||||
QVariant SavedAddressesModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if ((role != Qt::DisplayRole && role != Qt::EditRole) || orientation != Qt::Horizontal)
|
||||
if (orientation != Qt::Horizontal)
|
||||
return QVariant();
|
||||
|
||||
switch (section)
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
case SavedAddressesModel::ADDRESS:
|
||||
return tr("MEMORY ADDRESS");
|
||||
case SavedAddressesModel::LABEL:
|
||||
return tr("LABEL");
|
||||
case SavedAddressesModel::DESCRIPTION:
|
||||
return tr("DESCRIPTION");
|
||||
default:
|
||||
return QVariant();
|
||||
switch (section)
|
||||
{
|
||||
case SavedAddressesModel::ADDRESS:
|
||||
return tr("MEMORY ADDRESS");
|
||||
case SavedAddressesModel::LABEL:
|
||||
return tr("LABEL");
|
||||
case SavedAddressesModel::DESCRIPTION:
|
||||
return tr("DESCRIPTION");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
if (role == Qt::UserRole)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case SavedAddressesModel::ADDRESS:
|
||||
return "MEMORY ADDRESS";
|
||||
case SavedAddressesModel::LABEL:
|
||||
return "LABEL";
|
||||
case SavedAddressesModel::DESCRIPTION:
|
||||
return "DESCRIPTION";
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::ItemFlags SavedAddressesModel::flags(const QModelIndex& index) const
|
||||
@@ -150,3 +170,32 @@ int SavedAddressesModel::columnCount(const QModelIndex&) const
|
||||
{
|
||||
return HeaderColumns::COLUMN_COUNT;
|
||||
}
|
||||
|
||||
void SavedAddressesModel::loadSavedAddressFromFieldList(QStringList fields)
|
||||
{
|
||||
if (fields.size() != SavedAddressesModel::HeaderColumns::COLUMN_COUNT)
|
||||
{
|
||||
Console.WriteLn("Debugger Saved Addresses Model: Invalid number of columns, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
const u32 address = fields[SavedAddressesModel::HeaderColumns::ADDRESS].toUInt(&ok, 16);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger Saved Addresses Model: Failed to parse address '%s', skipping", fields[SavedAddressesModel::HeaderColumns::ADDRESS].toUtf8().constData());
|
||||
return;
|
||||
}
|
||||
|
||||
const QString label = fields[SavedAddressesModel::HeaderColumns::LABEL];
|
||||
const QString description = fields[SavedAddressesModel::HeaderColumns::DESCRIPTION];
|
||||
const SavedAddressesModel::SavedAddress importedAddress = {address, label, description};
|
||||
addRow(importedAddress);
|
||||
}
|
||||
|
||||
void SavedAddressesModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
m_savedAddresses.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
QString description;
|
||||
};
|
||||
|
||||
enum HeaderColumns : int
|
||||
enum HeaderColumns: int
|
||||
{
|
||||
ADDRESS = 0,
|
||||
LABEL,
|
||||
@@ -45,6 +45,8 @@ public:
|
||||
void addRow(SavedAddress addresstoSave);
|
||||
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
|
||||
void loadSavedAddressFromFieldList(QStringList fields);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
DebugInterface& m_cpu;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include "pcsx2/ImGui/FullscreenUI.h"
|
||||
#include "pcsx2/ImGui/ImGuiManager.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
@@ -323,8 +324,9 @@ bool DisplayWidget::event(QEvent* event)
|
||||
// don't toggle fullscreen when we're bound.. that wouldn't end well.
|
||||
if (event->type() == QEvent::MouseButtonDblClick &&
|
||||
static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton &&
|
||||
QtHost::IsVMValid() && !QtHost::IsVMPaused() &&
|
||||
!InputManager::HasAnyBindingsForKey(InputManager::MakePointerButtonKey(0, 0)) &&
|
||||
QtHost::IsVMValid() && !FullscreenUI::HasActiveWindow() &&
|
||||
((!QtHost::IsVMPaused() && !InputManager::HasAnyBindingsForKey(InputManager::MakePointerButtonKey(0, 0))) ||
|
||||
(QtHost::IsVMPaused() && !ImGuiManager::WantsMouseInput())) &&
|
||||
Host::GetBoolSettingValue("UI", "DoubleClickTogglesFullscreen", true))
|
||||
{
|
||||
g_emu_thread->toggleFullscreen();
|
||||
|
||||
+43
-21
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "AboutDialog.h"
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "Settings/ControllerSettingsWindow.h"
|
||||
#include "Settings/GameListSettingsWidget.h"
|
||||
#include "Settings/InterfaceSettingsWidget.h"
|
||||
#include "Settings/MemoryCardCreateDialog.h"
|
||||
#include "Tools/InputRecording/InputRecordingViewer.h"
|
||||
#include "Tools/InputRecording/NewInputRecordingDlg.h"
|
||||
#include "svnrev.h"
|
||||
@@ -178,11 +179,8 @@ QWidget* MainWindow::getContentParent()
|
||||
|
||||
void MainWindow::setupAdditionalUi()
|
||||
{
|
||||
const bool show_advanced_settings = QtHost::ShouldShowAdvancedSettings();
|
||||
|
||||
makeIconsMasks(menuBar());
|
||||
|
||||
m_ui.menuDebug->menuAction()->setVisible(show_advanced_settings);
|
||||
updateAdvancedSettingsVisibility();
|
||||
|
||||
const bool toolbar_visible = Host::GetBaseBoolSettingValue("UI", "ShowToolbar", false);
|
||||
m_ui.actionViewToolbar->setChecked(toolbar_visible);
|
||||
@@ -367,14 +365,18 @@ void MainWindow::connectSignals()
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionViewStatusBarVerbose, "UI", "VerboseStatusBar", false);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableSystemConsole, "Logging", "EnableSystemConsole", false);
|
||||
#ifdef _WIN32
|
||||
// Debug console only exists on Windows.
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableDebugConsole, "Logging", "EnableDebugConsole", false);
|
||||
#else
|
||||
m_ui.menuTools->removeAction(m_ui.actionEnableDebugConsole);
|
||||
m_ui.actionEnableDebugConsole->deleteLater();
|
||||
m_ui.actionEnableDebugConsole = nullptr;
|
||||
#endif
|
||||
|
||||
if (Log::IsDebugOutputAvailable())
|
||||
{
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableDebugConsole, "Logging", "EnableDebugConsole", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.menuTools->removeAction(m_ui.actionEnableDebugConsole);
|
||||
m_ui.actionEnableDebugConsole->deleteLater();
|
||||
m_ui.actionEnableDebugConsole = nullptr;
|
||||
}
|
||||
|
||||
#ifndef PCSX2_DEVBUILD
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableVerboseLogging, "Logging", "EnableVerbose", false);
|
||||
#else
|
||||
@@ -438,6 +440,7 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
|
||||
connect(thread, &EmuThread::onAchievementsLoginSucceeded, this, &MainWindow::onAchievementsLoginSucceeded);
|
||||
connect(thread, &EmuThread::onAchievementsHardcoreModeChanged, this, &MainWindow::onAchievementsHardcoreModeChanged);
|
||||
connect(thread, &EmuThread::onCoverDownloaderOpenRequested, this, &MainWindow::onToolsCoverDownloaderTriggered);
|
||||
connect(thread, &EmuThread::onCreateMemoryCardOpenRequested, this, &MainWindow::onCreateMemoryCardOpenRequested);
|
||||
|
||||
connect(m_ui.actionReset, &QAction::triggered, this, &MainWindow::requestReset);
|
||||
connect(m_ui.actionPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
|
||||
@@ -613,13 +616,13 @@ void MainWindow::onBlockDumpActionToggled(bool checked)
|
||||
if (!checked)
|
||||
return;
|
||||
|
||||
std::string old_directory(Host::GetBaseStringSettingValue("EmuCore", "BlockDumpSaveDirectory", ""));
|
||||
std::string old_directory = Host::GetBaseStringSettingValue("EmuCore", "BlockDumpSaveDirectory", "");
|
||||
if (old_directory.empty())
|
||||
old_directory = FileSystem::GetWorkingDirectory();
|
||||
|
||||
// prompt for a location to save
|
||||
const QString new_dir(
|
||||
QFileDialog::getExistingDirectory(this, tr("Select location to save block dump:"), QString::fromStdString(old_directory)));
|
||||
const QString new_dir(QDir::toNativeSeparators(
|
||||
QFileDialog::getExistingDirectory(this, tr("Select location to save block dump:"), QString::fromStdString(old_directory))));
|
||||
if (new_dir.isEmpty())
|
||||
{
|
||||
// disable it again
|
||||
@@ -669,13 +672,25 @@ void MainWindow::onShowAdvancedSettingsToggled(bool checked)
|
||||
Host::SetBaseBoolSettingValue("UI", "ShowAdvancedSettings", checked);
|
||||
Host::CommitBaseSettingChanges();
|
||||
|
||||
m_ui.menuDebug->menuAction()->setVisible(checked);
|
||||
updateAdvancedSettingsVisibility();
|
||||
|
||||
// just recreate the entire settings window, it's easier.
|
||||
if (m_settings_window)
|
||||
recreateSettings();
|
||||
}
|
||||
|
||||
void MainWindow::updateAdvancedSettingsVisibility()
|
||||
{
|
||||
const bool enabled = QtHost::ShouldShowAdvancedSettings();
|
||||
|
||||
m_ui.menuDebug->menuAction()->setVisible(enabled);
|
||||
|
||||
m_ui.actionEnableSystemConsole->setVisible(enabled);
|
||||
if (m_ui.actionEnableDebugConsole)
|
||||
m_ui.actionEnableDebugConsole->setVisible(enabled);
|
||||
m_ui.actionEnableVerboseLogging->setVisible(enabled);
|
||||
}
|
||||
|
||||
void MainWindow::onToolsVideoCaptureToggled(bool checked)
|
||||
{
|
||||
if (!s_vm_valid)
|
||||
@@ -1303,11 +1318,10 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
||||
});
|
||||
}
|
||||
|
||||
//: Refers to the directory where a game is contained.
|
||||
action = menu.addAction(tr("Open Containing Directory..."));
|
||||
action = menu.addAction(QtUtils::GetShowInFileExplorerMessage());
|
||||
connect(action, &QAction::triggered, [this, entry]() {
|
||||
const QFileInfo fi(QString::fromStdString(entry->path));
|
||||
QtUtils::OpenURL(this, QUrl::fromLocalFile(fi.absolutePath()));
|
||||
QtUtils::ShowInFileExplorer(this, fi);
|
||||
});
|
||||
|
||||
action = menu.addAction(tr("Set Cover Image..."));
|
||||
@@ -1627,7 +1641,7 @@ void MainWindow::onToolsCoverDownloaderTriggered()
|
||||
{
|
||||
// This can be invoked via big picture, so exit fullscreen.
|
||||
VMLock lock(pauseAndLockVM());
|
||||
CoverDownloadDialog dlg(this);
|
||||
CoverDownloadDialog dlg(lock.getDialogParent());
|
||||
connect(&dlg, &CoverDownloadDialog::coverRefreshRequested, m_game_list_widget, &GameListWidget::refreshGridCovers);
|
||||
dlg.exec();
|
||||
}
|
||||
@@ -1658,6 +1672,14 @@ void MainWindow::onToolsEditCheatsPatchesTriggered(bool cheats)
|
||||
QtUtils::OpenURL(this, QUrl::fromLocalFile(QString::fromStdString(path)));
|
||||
}
|
||||
|
||||
void MainWindow::onCreateMemoryCardOpenRequested()
|
||||
{
|
||||
// This can be invoked via big picture, so exit fullscreen.
|
||||
VMLock lock(pauseAndLockVM());
|
||||
MemoryCardCreateDialog dlg(lock.getDialogParent());
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void MainWindow::updateTheme()
|
||||
{
|
||||
QtHost::UpdateApplicationTheme();
|
||||
|
||||
@@ -158,6 +158,7 @@ private Q_SLOTS:
|
||||
void onToolsOpenDataDirectoryTriggered();
|
||||
void onToolsCoverDownloaderTriggered();
|
||||
void onToolsEditCheatsPatchesTriggered(bool cheats);
|
||||
void onCreateMemoryCardOpenRequested();
|
||||
void updateTheme();
|
||||
void reloadThemeSpecificImages();
|
||||
void updateLanguage();
|
||||
@@ -222,6 +223,7 @@ private:
|
||||
void updateDisplayRelatedActions(bool has_surface, bool render_to_main, bool fullscreen);
|
||||
void updateGameDependentActions();
|
||||
void updateStatusBarWidgetVisibility();
|
||||
void updateAdvancedSettingsVisibility();
|
||||
void updateWindowTitle();
|
||||
void updateWindowState(bool force_visible = false);
|
||||
void setProgressBar(int current, int total);
|
||||
|
||||
@@ -1089,11 +1089,19 @@
|
||||
<property name="text">
|
||||
<string>Edit Cheats...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="pencil-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEditPatches">
|
||||
<property name="text">
|
||||
<string>Edit Patches...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="pencil-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
|
||||
+15
-25
@@ -29,7 +29,6 @@
|
||||
#include "pcsx2/Input/InputManager.h"
|
||||
#include "pcsx2/MTGS.h"
|
||||
#include "pcsx2/PerformanceMetrics.h"
|
||||
#include "pcsx2/SysForwardDefs.h"
|
||||
#include "pcsx2/VMManager.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
@@ -88,6 +87,7 @@ static bool s_start_fullscreen_ui = false;
|
||||
static bool s_start_fullscreen_ui_fullscreen = false;
|
||||
static bool s_test_config_and_exit = false;
|
||||
static bool s_run_setup_wizard = false;
|
||||
static bool s_cleanup_after_update = false;
|
||||
static bool s_boot_and_debug = false;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -497,7 +497,7 @@ void EmuThread::setFullscreen(bool fullscreen, bool allow_render_to_main)
|
||||
MTGS::WaitGS();
|
||||
|
||||
// If we're using exclusive fullscreen, the refresh rate may have changed.
|
||||
UpdateVSyncRate(true);
|
||||
VMManager::UpdateTargetSpeed();
|
||||
}
|
||||
|
||||
void EmuThread::setSurfaceless(bool surfaceless)
|
||||
@@ -1117,7 +1117,12 @@ void Host::OnCoverDownloaderOpenRequested()
|
||||
emit g_emu_thread->onCoverDownloaderOpenRequested();
|
||||
}
|
||||
|
||||
void Host::VSyncOnCPUThread()
|
||||
void Host::OnCreateMemoryCardOpenRequested()
|
||||
{
|
||||
emit g_emu_thread->onCreateMemoryCardOpenRequested();
|
||||
}
|
||||
|
||||
void Host::PumpMessagesOnCPUThread()
|
||||
{
|
||||
g_emu_thread->getEventLoop()->processEvents(QEventLoop::AllEvents);
|
||||
}
|
||||
@@ -1336,24 +1341,7 @@ bool Host::RequestResetSettings(bool folders, bool core, bool controllers, bool
|
||||
|
||||
QString QtHost::GetAppNameAndVersion()
|
||||
{
|
||||
QString ret;
|
||||
if constexpr (!PCSX2_isReleaseVersion && GIT_TAGGED_COMMIT)
|
||||
{
|
||||
ret = QStringLiteral("PCSX2 Nightly - " GIT_TAG);
|
||||
}
|
||||
else if constexpr (PCSX2_isReleaseVersion)
|
||||
{
|
||||
#define APPNAME_STRINGIZE(x) #x
|
||||
ret = QStringLiteral(
|
||||
"PCSX2 " APPNAME_STRINGIZE(PCSX2_VersionHi) "." APPNAME_STRINGIZE(PCSX2_VersionMid) "." APPNAME_STRINGIZE(PCSX2_VersionLo));
|
||||
#undef APPNAME_STRINGIZE
|
||||
}
|
||||
else
|
||||
{
|
||||
return QStringLiteral("PCSX2 " GIT_REV);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return QStringLiteral("PCSX2 " GIT_REV);
|
||||
}
|
||||
|
||||
QString QtHost::GetAppConfigSuffix()
|
||||
@@ -1398,7 +1386,7 @@ std::optional<bool> QtHost::DownloadFile(QWidget* parent, const QString& title,
|
||||
QtModalProgressCallback progress(parent);
|
||||
progress.GetDialog().setLabelText(
|
||||
qApp->translate("EmuThread", "Downloading %1...").arg(QtUtils::StringViewToQString(
|
||||
std::string_view(url).substr((url_file_part_pos >= 0) ? (url_file_part_pos + 1) : 0))));
|
||||
std::string_view(url).substr((url_file_part_pos != std::string::npos) ? (url_file_part_pos + 1) : 0))));
|
||||
progress.GetDialog().setWindowTitle(title);
|
||||
progress.GetDialog().setWindowIcon(GetAppIcon());
|
||||
progress.SetCancellable(true);
|
||||
@@ -1778,9 +1766,7 @@ bool QtHost::ParseCommandLineOptions(const QStringList& args, std::shared_ptr<VM
|
||||
}
|
||||
else if (CHECK_ARG(QStringLiteral("-updatecleanup")))
|
||||
{
|
||||
if (AutoUpdaterDialog::isSupported())
|
||||
AutoUpdaterDialog::cleanupAfterUpdate();
|
||||
|
||||
s_cleanup_after_update = AutoUpdaterDialog::isSupported();
|
||||
continue;
|
||||
}
|
||||
#ifdef ENABLE_RAINTEGRATION
|
||||
@@ -1911,6 +1897,10 @@ int main(int argc, char* argv[])
|
||||
if (s_test_config_and_exit)
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
// Remove any previous-version remanants.
|
||||
if (s_cleanup_after_update)
|
||||
AutoUpdaterDialog::cleanupAfterUpdate();
|
||||
|
||||
// Set theme before creating any windows.
|
||||
QtHost::UpdateApplicationTheme();
|
||||
|
||||
|
||||
+2
-1
@@ -168,8 +168,9 @@ Q_SIGNALS:
|
||||
/// Called when hardcore mode is enabled or disabled.
|
||||
void onAchievementsHardcoreModeChanged(bool enabled);
|
||||
|
||||
/// Called when cover download is requested.
|
||||
/// Big Picture UI requests.
|
||||
void onCoverDownloaderOpenRequested();
|
||||
void onCreateMemoryCardOpenRequested();
|
||||
|
||||
/// Called when video capture starts/stops.
|
||||
void onCaptureStarted(const QString& filename);
|
||||
|
||||
+41
-2
@@ -4,6 +4,7 @@
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QMetaObject>
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QGuiApplication>
|
||||
@@ -26,10 +27,12 @@
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
#include "common/CocoaTools.h"
|
||||
#include "common/Console.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include <Shlobj.h>
|
||||
#elif !defined(APPLE)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
@@ -129,12 +132,48 @@ namespace QtUtils
|
||||
ResizeColumnsForView(view, widths);
|
||||
}
|
||||
|
||||
void ShowInFileExplorer(QWidget* parent, const QFileInfo& file)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
std::wstring wstr = QDir::toNativeSeparators(file.absoluteFilePath()).toStdWString();
|
||||
bool ok = false;
|
||||
if (PIDLIST_ABSOLUTE pidl = ILCreateFromPath(wstr.c_str()))
|
||||
{
|
||||
ok = SUCCEEDED(SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0));
|
||||
ILFree(pidl);
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
bool ok = CocoaTools::ShowInFinder(file.absoluteFilePath().toStdString());
|
||||
#else
|
||||
bool ok = QDesktopServices::openUrl(QUrl::fromLocalFile(file.absolutePath()));
|
||||
#endif
|
||||
if (!ok)
|
||||
{
|
||||
QMessageBox::critical(parent, QCoreApplication::translate("FileOperations", "Failed to show file"),
|
||||
QCoreApplication::translate("FileOperations", "Failed to show file in file explorer.\n\nThe file was: %1").arg(file.absoluteFilePath()));
|
||||
}
|
||||
}
|
||||
|
||||
QString GetShowInFileExplorerMessage()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
//: Windows action to show a file in Windows Explorer
|
||||
return QCoreApplication::translate("FileOperations", "Show in Folder");
|
||||
#elif defined(__APPLE__)
|
||||
//: macOS action to show a file in Finder
|
||||
return QCoreApplication::translate("FileOperations", "Show in Finder");
|
||||
#else
|
||||
//: Opens the system file manager to the directory containing a selected file
|
||||
return QCoreApplication::translate("FileOperations", "Open Containing Directory");
|
||||
#endif
|
||||
}
|
||||
|
||||
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()));
|
||||
QMessageBox::critical(parent, QCoreApplication::translate("FileOperations", "Failed to open URL"),
|
||||
QCoreApplication::translate("FileOperations", "Failed to open URL.\n\nThe URL was: %1").arg(qurl.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ class ByteStream;
|
||||
|
||||
class QAction;
|
||||
class QComboBox;
|
||||
class QFileInfo;
|
||||
class QFrame;
|
||||
class QKeyEvent;
|
||||
class QTableView;
|
||||
@@ -49,6 +50,12 @@ namespace QtUtils
|
||||
/// NOTE: Defined in QtKeyCodes.cpp, not QtUtils.cpp.
|
||||
u32 KeyEventToCode(const QKeyEvent* ev);
|
||||
|
||||
/// Shows a file, or the containing folder if unsupported, with the system file explorer
|
||||
void ShowInFileExplorer(QWidget* parent, const QFileInfo& file);
|
||||
|
||||
/// Get the context menu name for the action performed by ShowInFileExplorer
|
||||
QString GetShowInFileExplorerMessage();
|
||||
|
||||
/// Opens a URL with the default handler.
|
||||
void OpenURL(QWidget* parent, const QUrl& qurl);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "Settings/ControllerGlobalSettingsWidget.h"
|
||||
@@ -40,7 +40,6 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||
#ifdef _WIN32
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableXInputSource, "InputSources", "XInput", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableDInputSource, "InputSources", "DInput", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.ignoreDInputInversion, "InputSources", "IgnoreDInputInversion", false);
|
||||
#else
|
||||
m_ui.mainLayout->removeWidget(m_ui.xinputGroup);
|
||||
m_ui.xinputGroup->deleteLater();
|
||||
@@ -176,3 +175,19 @@ ControllerMouseSettingsDialog::ControllerMouseSettingsDialog(QWidget* parent, Co
|
||||
}
|
||||
|
||||
ControllerMouseSettingsDialog::~ControllerMouseSettingsDialog() = default;
|
||||
|
||||
ControllerMappingSettingsDialog::ControllerMappingSettingsDialog(ControllerSettingsWindow* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
SettingsInterface* sif = parent->getProfileSettingsInterface();
|
||||
|
||||
m_ui.icon->setPixmap(QIcon::fromTheme(QStringLiteral("settings-3-line")).pixmap(32, 32));
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.ignoreInversion, "InputSources", "IgnoreInversion", false);
|
||||
|
||||
connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept);
|
||||
}
|
||||
|
||||
ControllerMappingSettingsDialog::~ControllerMappingSettingsDialog() = default;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#pragma once
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "ui_ControllerGlobalSettingsWidget.h"
|
||||
#include "ui_ControllerLEDSettingsDialog.h"
|
||||
#include "ui_ControllerMappingSettingsDialog.h"
|
||||
#include "ui_ControllerMouseSettingsDialog.h"
|
||||
|
||||
class ControllerSettingsWindow;
|
||||
@@ -66,3 +67,15 @@ public:
|
||||
private:
|
||||
Ui::ControllerMouseSettingsDialog m_ui;
|
||||
};
|
||||
|
||||
class ControllerMappingSettingsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ControllerMappingSettingsDialog(ControllerSettingsWindow* parent);
|
||||
~ControllerMappingSettingsDialog();
|
||||
|
||||
private:
|
||||
Ui::ControllerMappingSettingsDialog m_ui;
|
||||
};
|
||||
|
||||
@@ -82,16 +82,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="ignoreDInputInversion">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Some third party controllers incorrectly flag their analog sticks as inverted on the positive component, but not negative.</p><p>As a result, the analog stick will be &quot;stuck on&quot; even while resting at neutral position. </p><p>Enabling this setting will tell PCSX2 to ignore inversion flags when creating mappings, allowing such controllers to function normally.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Ignore Inversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ControllerMappingSettingsDialog</class>
|
||||
<widget class="QDialog" name="ControllerMappingSettingsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>654</width>
|
||||
<height>275</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Controller Mapping Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="icon">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:700;">Controller Mapping Settings</span><br/>These settings fine-tune the behavior when mapping physical controllers to the emulated controllers.</p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ignoreInversion">
|
||||
<property name="text">
|
||||
<string>Ignore Inversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Some third party controllers incorrectly flag their analog sticks as inverted on the positive component, but not negative.</p><p>As a result, the analog stick will be &quot;stuck on&quot; even while resting at neutral position. </p><p>Enabling this setting will tell PCSX2 to ignore inversion flags when creating mappings, allowing such controllers to function normally.</p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</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>28</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
@@ -39,6 +39,7 @@ ControllerSettingsWindow::ControllerSettingsWindow()
|
||||
connect(m_ui.newProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onNewProfileClicked);
|
||||
connect(m_ui.loadProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onLoadProfileClicked);
|
||||
connect(m_ui.deleteProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onDeleteProfileClicked);
|
||||
connect(m_ui.mappingSettings, &QPushButton::clicked, this, &ControllerSettingsWindow::onMappingSettingsClicked);
|
||||
connect(m_ui.restoreDefaults, &QPushButton::clicked, this, &ControllerSettingsWindow::onRestoreDefaultsClicked);
|
||||
|
||||
connect(g_emu_thread, &EmuThread::onInputDevicesEnumerated, this, &ControllerSettingsWindow::onInputDevicesEnumerated);
|
||||
@@ -186,6 +187,12 @@ void ControllerSettingsWindow::onDeleteProfileClicked()
|
||||
switchProfile({});
|
||||
}
|
||||
|
||||
void ControllerSettingsWindow::onMappingSettingsClicked()
|
||||
{
|
||||
ControllerMappingSettingsDialog dialog(this);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void ControllerSettingsWindow::onRestoreDefaultsClicked()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Restore Defaults"),
|
||||
|
||||
@@ -76,6 +76,7 @@ private Q_SLOTS:
|
||||
void onNewProfileClicked();
|
||||
void onLoadProfileClicked();
|
||||
void onDeleteProfileClicked();
|
||||
void onMappingSettingsClicked();
|
||||
void onRestoreDefaultsClicked();
|
||||
|
||||
void onInputDevicesEnumerated(const QList<QPair<QString, QString>>& devices);
|
||||
|
||||
@@ -123,6 +123,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="mappingSettings">
|
||||
<property name="text">
|
||||
<string>Mapping Settings</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="settings-3-line"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="restoreDefaults">
|
||||
<property name="text">
|
||||
|
||||
@@ -253,6 +253,8 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsWindow* dialog, QWidget* parent)
|
||||
else
|
||||
m_ui.hddFile->setText(QString::fromUtf8(m_dialog->getStringValue("DEV9/Hdd", "HddFile", "DEV9hdd.raw").value().c_str()));
|
||||
|
||||
connect(m_ui.hddLBA48, QOverload<int>::of(&QCheckBox::stateChanged), this, &DEV9SettingsWidget::onHddLBA48Changed);
|
||||
|
||||
UpdateHddSizeUIValues();
|
||||
|
||||
connect(m_ui.hddFile, &QLineEdit::textChanged, this, &DEV9SettingsWidget::onHddFileTextChange);
|
||||
@@ -720,6 +722,19 @@ void DEV9SettingsWidget::onHddSizeAccessorSpin()
|
||||
m_ui.hddSizeSlider->setValue(m_ui.hddSizeSpinBox->value());
|
||||
}
|
||||
|
||||
void DEV9SettingsWidget::onHddLBA48Changed(int state)
|
||||
{
|
||||
m_ui.hddSizeSlider->setMaximum(state ? 2000 : 120);
|
||||
m_ui.hddSizeSpinBox->setMaximum(state ? 2000 : 120);
|
||||
m_ui.hddSizeMaxLabel->setText(state ? tr("2000") : tr("120"));
|
||||
// Bump up min size to have ticks align with 100GiB sizes
|
||||
m_ui.hddSizeSlider->setMinimum(state ? 100 : 40);
|
||||
m_ui.hddSizeSpinBox->setMinimum(state ? 100 : 40);
|
||||
m_ui.hddSizeMinLabel->setText(state ? tr("100") : tr("40"));
|
||||
|
||||
m_ui.hddSizeSlider->setTickInterval(state ? 100 : 5);
|
||||
}
|
||||
|
||||
void DEV9SettingsWidget::onHddCreateClicked()
|
||||
{
|
||||
//Do the thing
|
||||
@@ -800,6 +815,11 @@ void DEV9SettingsWidget::UpdateHddSizeUIValues()
|
||||
if (size < 0)
|
||||
return;
|
||||
|
||||
if (size > static_cast<s64>(120) * 1024 * 1024 * 1024)
|
||||
m_ui.hddLBA48->setChecked(true);
|
||||
else
|
||||
m_ui.hddLBA48->setChecked(false);
|
||||
|
||||
const int sizeGB = size / 1024 / 1024 / 1024;
|
||||
QSignalBlocker sb1(m_ui.hddSizeSpinBox);
|
||||
QSignalBlocker sb2(m_ui.hddSizeSlider);
|
||||
|
||||
@@ -39,6 +39,7 @@ private Q_SLOTS:
|
||||
void onHddFileEdit();
|
||||
void onHddSizeSlide(int i);
|
||||
void onHddSizeAccessorSpin();
|
||||
void onHddLBA48Changed(int state);
|
||||
void onHddCreateClicked();
|
||||
|
||||
public:
|
||||
|
||||
@@ -365,6 +365,20 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="hddLBA48Label">
|
||||
<property name="text">
|
||||
<string>48-bit LBA:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="hddLBA48">
|
||||
<property name="text">
|
||||
<string>Enabled</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -32,6 +32,9 @@ GameCheatSettingsWidget::GameCheatSettingsWidget(SettingsWindow* dialog, QWidget
|
||||
connect(m_ui.enableAll, &QPushButton::clicked, this, [this]() { setStateForAll(true); });
|
||||
connect(m_ui.disableAll, &QPushButton::clicked, this, [this]() { setStateForAll(false); });
|
||||
connect(m_ui.allCRCsCheckbox, &QCheckBox::stateChanged, this, &GameCheatSettingsWidget::onReloadClicked);
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.allCRCsCheckbox, tr("Show Cheats For All CRCs"), tr("Checked"),
|
||||
tr("Toggles scanning patch files for all CRCs of the game. With this enabled available patches for the game serial with different CRCs will also be loaded."));
|
||||
}
|
||||
|
||||
GameCheatSettingsWidget::~GameCheatSettingsWidget() = default;
|
||||
|
||||
@@ -63,6 +63,9 @@ GamePatchSettingsWidget::GamePatchSettingsWidget(SettingsWindow* dialog, QWidget
|
||||
connect(m_ui.reload, &QPushButton::clicked, this, &GamePatchSettingsWidget::onReloadClicked);
|
||||
connect(m_ui.allCRCsCheckbox, &QCheckBox::stateChanged, this, &GamePatchSettingsWidget::reloadList);
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.allCRCsCheckbox, tr("Show Patches For All CRCs"), tr("Checked"),
|
||||
tr("Toggles scanning patch files for all CRCs of the game. With this enabled available patches for the game serial with different CRCs will also be loaded."));
|
||||
|
||||
reloadList();
|
||||
}
|
||||
|
||||
|
||||
@@ -300,6 +300,26 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get rid of widescreen/no-interlace checkboxes from per-game settings, unless the user previously had them set.
|
||||
if (m_dialog->isPerGameSettings())
|
||||
{
|
||||
if ((m_dialog->containsSettingValue("EmuCore", "EnableWideScreenPatches") || m_dialog->containsSettingValue("EmuCore", "EnableNoInterlacingPatches")) &&
|
||||
QMessageBox::question(QtUtils::GetRootWidget(this), tr("Remove Unsupported Settings"),
|
||||
tr("You currently have the <strong>Enable Widescreen Patches</strong> or <strong>Enable No-Interlacing Patches</strong> options enabled for this game.<br><br>"
|
||||
"We no longer support these options, instead <strong>you should select the \"Patches\" section, and explicitly enable the patches you want.</strong><br><br>"
|
||||
"Do you want to remove these options from your game configuration now?"),
|
||||
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
|
||||
{
|
||||
m_dialog->removeSettingValue("EmuCore", "EnableWideScreenPatches");
|
||||
m_dialog->removeSettingValue("EmuCore", "EnableNoInterlacingPatches");
|
||||
}
|
||||
|
||||
m_ui.gridLayout->removeWidget(m_ui.widescreenPatches);
|
||||
m_ui.gridLayout->removeWidget(m_ui.noInterlacingPatches);
|
||||
safe_delete(m_ui.widescreenPatches);
|
||||
safe_delete(m_ui.noInterlacingPatches);
|
||||
}
|
||||
|
||||
// Hide advanced options by default.
|
||||
if (!QtHost::ShouldShowAdvancedSettings())
|
||||
{
|
||||
@@ -714,7 +734,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||
|
||||
"<b>If unsure, leave it on default.<b>"));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.audioCaptureBitrate, tr("Audio Bitrate"), tr("160 Kbps"), tr("Sets the audio bitrate to be used."));
|
||||
dialog->registerWidgetHelp(m_ui.audioCaptureBitrate, tr("Audio Bitrate"), tr("160 kbps"), tr("Sets the audio bitrate to be used."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.enableAudioCaptureArguments, tr("Enable Extra Audio Arguments"), tr("Unchecked"), tr("Allows you to pass arguments to the selected audio codec."));
|
||||
|
||||
|
||||
@@ -324,7 +324,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<layout class="QGridLayout" name="displayGridLayout">
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="PCRTCOffsets">
|
||||
<property name="text">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "common/FileSystem.h"
|
||||
@@ -36,7 +36,13 @@ MemoryCardCreateDialog::MemoryCardCreateDialog(QWidget* parent /* = nullptr */)
|
||||
connect(m_ui.buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &MemoryCardCreateDialog::restoreDefaults);
|
||||
|
||||
#ifndef _WIN32
|
||||
m_ui.ntfsCompression->setEnabled(false);
|
||||
m_ui.ntfsCompressionLayout->removeWidget(m_ui.ntfsCompression);
|
||||
safe_delete(m_ui.ntfsCompression);
|
||||
m_ui.ntfsCompressionLayout->removeWidget(m_ui.ntfsCompressionLabel);
|
||||
safe_delete(m_ui.ntfsCompressionLabel);
|
||||
m_ui.mainLayout->removeItem(m_ui.ntfsCompressionLayout);
|
||||
safe_delete(m_ui.ntfsCompressionLayout);
|
||||
resize(600, 480);
|
||||
#endif
|
||||
|
||||
updateState();
|
||||
@@ -117,10 +123,10 @@ void MemoryCardCreateDialog::createCard()
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (m_ui.ntfsCompression->isChecked() && m_type == MemoryCardType::File)
|
||||
if (m_type == MemoryCardType::File)
|
||||
{
|
||||
const std::string fullPath(Path::Combine(EmuFolders::MemoryCards, name_str));
|
||||
FileSystem::SetPathCompression(fullPath.c_str(), true);
|
||||
const std::string fullPath = Path::Combine(EmuFolders::MemoryCards, name_str);
|
||||
FileSystem::SetPathCompression(fullPath.c_str(), m_ui.ntfsCompression->isChecked());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>593</width>
|
||||
<height>545</height>
|
||||
<width>600</width>
|
||||
<height>535</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -16,13 +16,13 @@
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<layout class="QVBoxLayout" name="mainLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
|
||||
<property name="bottomMargin">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
@@ -39,8 +39,8 @@
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="resources/resources.qrc">:/icons/black/svg/memcard-line.svg</pixmap>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../resources/resources.qrc">:/icons/black/svg/memcard-line.svg</pixmap>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
@@ -227,7 +227,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<layout class="QVBoxLayout" name="ntfsCompressionLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ntfsCompression">
|
||||
<property name="text">
|
||||
@@ -239,7 +239,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<widget class="QLabel" name="ntfsCompressionLabel">
|
||||
<property name="text">
|
||||
<string>NTFS compression is built-in, fast, and completely reliable. Typically compresses Memory Cards (highly recommended).</string>
|
||||
</property>
|
||||
|
||||
@@ -54,7 +54,6 @@ MemoryCardSettingsWidget::MemoryCardSettingsWidget(SettingsWindow* dialog, QWidg
|
||||
|
||||
connect(m_ui.refreshCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::refresh);
|
||||
connect(m_ui.createCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::createCard);
|
||||
connect(m_ui.duplicateCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::duplicateCard);
|
||||
connect(m_ui.renameCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::renameCard);
|
||||
connect(m_ui.convertCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::convertCard);
|
||||
connect(m_ui.deleteCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::deleteCard);
|
||||
@@ -89,22 +88,22 @@ void MemoryCardSettingsWidget::setupAdditionalUi()
|
||||
createSlotWidgets(&m_slots[i], i);
|
||||
|
||||
// button to swap Memory Cards
|
||||
QToolButton* swap_button = new QToolButton(m_ui.portGroupBox);
|
||||
QToolButton* swap_button = new QToolButton(m_ui.slotGroupBox);
|
||||
swap_button->setIcon(QIcon::fromTheme("arrow-left-right-line"));
|
||||
swap_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||
swap_button->setToolTip(tr("Swap Memory Cards"));
|
||||
connect(swap_button, &QToolButton::clicked, this, &MemoryCardSettingsWidget::swapCards);
|
||||
static_cast<QGridLayout*>(m_ui.portGroupBox->layout())->addWidget(swap_button, 0, 1);
|
||||
static_cast<QGridLayout*>(m_ui.slotGroupBox->layout())->addWidget(swap_button, 0, 1);
|
||||
}
|
||||
|
||||
void MemoryCardSettingsWidget::createSlotWidgets(SlotGroup* port, u32 slot)
|
||||
{
|
||||
const bool perGame = m_dialog->isPerGameSettings();
|
||||
|
||||
port->root = new QWidget(m_ui.portGroupBox);
|
||||
port->root = new QWidget(m_ui.slotGroupBox);
|
||||
|
||||
SettingsInterface* sif = m_dialog->getSettingsInterface();
|
||||
port->enable = new QCheckBox(tr("Port %1").arg(slot + 1), port->root);
|
||||
port->enable = new QCheckBox(tr("Slot %1").arg(slot + 1), port->root);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, port->enable, CONFIG_SECTION, StringUtil::StdStringFromFormat("Slot%u_Enable", slot + 1), true);
|
||||
connect(port->enable, &QCheckBox::stateChanged, this, &MemoryCardSettingsWidget::refresh);
|
||||
@@ -129,7 +128,7 @@ void MemoryCardSettingsWidget::createSlotWidgets(SlotGroup* port, u32 slot)
|
||||
vert_layout->addWidget(port->enable, 0);
|
||||
vert_layout->addLayout(bottom_layout, 1);
|
||||
|
||||
static_cast<QGridLayout*>(m_ui.portGroupBox->layout())->addWidget(port->root, 0, (slot != 0) ? 2 : 0);
|
||||
static_cast<QGridLayout*>(m_ui.slotGroupBox->layout())->addWidget(port->root, 0, (slot != 0) ? 2 : 0);
|
||||
}
|
||||
|
||||
void MemoryCardSettingsWidget::autoSizeUI()
|
||||
@@ -193,20 +192,10 @@ void MemoryCardSettingsWidget::updateCardActions()
|
||||
bool isPS1 = (cardInfo.has_value() ? cardInfo.value().file_type == MemoryCardFileType::PS1 : false);
|
||||
|
||||
m_ui.convertCard->setEnabled(hasSelection && !isPS1);
|
||||
m_ui.duplicateCard->setEnabled(hasSelection);
|
||||
m_ui.renameCard->setEnabled(hasSelection);
|
||||
m_ui.deleteCard->setEnabled(hasSelection);
|
||||
}
|
||||
|
||||
void MemoryCardSettingsWidget::duplicateCard()
|
||||
{
|
||||
const QString selectedCard(getSelectedCard());
|
||||
if (selectedCard.isEmpty())
|
||||
return;
|
||||
|
||||
QMessageBox::critical(this, tr("Error"), tr("Not yet implemented."));
|
||||
}
|
||||
|
||||
void MemoryCardSettingsWidget::deleteCard()
|
||||
{
|
||||
const QString selectedCard(getSelectedCard());
|
||||
@@ -289,12 +278,11 @@ void MemoryCardSettingsWidget::listContextMenuRequested(const QPoint& pos)
|
||||
{
|
||||
for (u32 slot = 0; slot < MAX_SLOTS; slot++)
|
||||
{
|
||||
connect(menu.addAction(tr("Use for Port %1").arg(slot + 1)), &QAction::triggered, this,
|
||||
connect(menu.addAction(tr("Use for Slot %1").arg(slot + 1)), &QAction::triggered, this,
|
||||
[this, &selectedCard, slot]() { tryInsertCard(slot, selectedCard); });
|
||||
}
|
||||
menu.addSeparator();
|
||||
|
||||
connect(menu.addAction(tr("Duplicate")), &QAction::triggered, this, &MemoryCardSettingsWidget::duplicateCard);
|
||||
connect(menu.addAction(tr("Rename")), &QAction::triggered, this, &MemoryCardSettingsWidget::renameCard);
|
||||
connect(menu.addAction(tr("Convert")), &QAction::triggered, this, &MemoryCardSettingsWidget::convertCard);
|
||||
connect(menu.addAction(tr("Delete")), &QAction::triggered, this, &MemoryCardSettingsWidget::deleteCard);
|
||||
@@ -336,7 +324,7 @@ void MemoryCardSettingsWidget::swapCards()
|
||||
if (!card1Name.has_value() || card1Name->empty() || !card2Name.has_value() || card2Name->empty())
|
||||
{
|
||||
QMessageBox::critical(
|
||||
QtUtils::GetRootWidget(this), tr("Error"), tr("Both ports must have a card selected to swap."));
|
||||
QtUtils::GetRootWidget(this), tr("Error"), tr("Both slots must have a card selected to swap."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,6 @@ private:
|
||||
|
||||
QString getSelectedCard() const;
|
||||
void updateCardActions();
|
||||
void duplicateCard();
|
||||
void deleteCard();
|
||||
void renameCard();
|
||||
void convertCard();
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="portGroupBox">
|
||||
<widget class="QGroupBox" name="slotGroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -44,7 +44,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Console Ports</string>
|
||||
<string>Memory Card Slots</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout"/>
|
||||
</widget>
|
||||
@@ -146,13 +146,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="duplicateCard">
|
||||
<property name="text">
|
||||
<string>Duplicate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="renameCard">
|
||||
<property name="text">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "MainWindow.h"
|
||||
@@ -32,7 +32,9 @@
|
||||
#include "common/Path.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include <QtGui/QWheelEvent>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QScrollBar>
|
||||
#include <QtWidgets/QTextEdit>
|
||||
|
||||
static QList<SettingsWindow*> s_open_game_properties_dialogs;
|
||||
@@ -110,7 +112,7 @@ void SettingsWindow::setupUi(const GameList::Entry* game)
|
||||
addWidget(m_interface_settings = new InterfaceSettingsWidget(this, m_ui.settingsContainer), tr("Interface"),
|
||||
QStringLiteral("interface-line"),
|
||||
tr("<strong>Interface Settings</strong><hr>These options control how the software looks and behaves.<br><br>Mouse over an option "
|
||||
"for additional information."));
|
||||
"for additional information, and Shift+Wheel to scroll this panel."));
|
||||
|
||||
// We don't include game list/bios settings in per-game settings.
|
||||
if (!isPerGameSettings())
|
||||
@@ -120,14 +122,15 @@ void SettingsWindow::setupUi(const GameList::Entry* game)
|
||||
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."));
|
||||
addWidget(m_bios_settings = new BIOSSettingsWidget(this, m_ui.settingsContainer), tr("BIOS"), QStringLiteral("chip-line"),
|
||||
tr("<strong>BIOS Settings</strong><hr>Configure your BIOS here.<br><br>Mouse over an option for additional information."));
|
||||
tr("<strong>BIOS Settings</strong><hr>Configure your BIOS here.<br><br>Mouse over an option for additional information, "
|
||||
"and Shift+Wheel to scroll this panel."));
|
||||
}
|
||||
|
||||
// Common to both per-game and global settings.
|
||||
addWidget(m_emulation_settings = new EmulationSettingsWidget(this, m_ui.settingsContainer), tr("Emulation"),
|
||||
QStringLiteral("emulation-line"),
|
||||
tr("<strong>Emulation Settings</strong><hr>These options determine the configuration of frame pacing and game "
|
||||
"settings.<br><br>Mouse over an option for additional information."));
|
||||
"settings.<br><br>Mouse over an option for additional information, and Shift+Wheel to scroll this panel."));
|
||||
|
||||
if (isPerGameSettings())
|
||||
{
|
||||
@@ -153,19 +156,19 @@ void SettingsWindow::setupUi(const GameList::Entry* game)
|
||||
|
||||
addWidget(m_graphics_settings = new GraphicsSettingsWidget(this, m_ui.settingsContainer), tr("Graphics"), QStringLiteral("image-fill"),
|
||||
tr("<strong>Graphics Settings</strong><hr>These options determine the configuration of the graphical output.<br><br>Mouse over an "
|
||||
"option for additional information."));
|
||||
"option for additional information, and Shift+Wheel to scroll this panel."));
|
||||
addWidget(m_audio_settings = new AudioSettingsWidget(this, m_ui.settingsContainer), tr("Audio"), QStringLiteral("volume-up-line"),
|
||||
tr("<strong>Audio Settings</strong><hr>These options control the audio output of the console.<br><br>Mouse over an option for "
|
||||
"additional information."));
|
||||
"additional information, and Shift+Wheel to scroll this panel."));
|
||||
|
||||
addWidget(m_memory_card_settings = new MemoryCardSettingsWidget(this, m_ui.settingsContainer), tr("Memory Cards"),
|
||||
QStringLiteral("memcard-line"),
|
||||
tr("<strong>Memory Card Settings</strong><hr>Create and configure Memory Cards here.<br><br>Mouse over an option for "
|
||||
"additional information."));
|
||||
"additional information, and Shift+Wheel to scroll this panel."));
|
||||
|
||||
addWidget(m_dev9_settings = new DEV9SettingsWidget(this, m_ui.settingsContainer), tr("Network & HDD"), QStringLiteral("global-line"),
|
||||
tr("<strong>Network & HDD Settings</strong><hr>These options control the network connectivity and internal HDD storage of the "
|
||||
"console.<br><br>Mouse over an option for additional information."));
|
||||
"console.<br><br>Mouse over an option for additional information, and Shift+Wheel to scroll this panel."));
|
||||
|
||||
if (!isPerGameSettings())
|
||||
{
|
||||
@@ -199,9 +202,9 @@ void SettingsWindow::setupUi(const GameList::Entry* game)
|
||||
addWidget(m_advanced_settings = new AdvancedSettingsWidget(this, m_ui.settingsContainer), tr("Advanced"),
|
||||
QStringLiteral("warning-line"),
|
||||
tr("<strong>Advanced Settings</strong><hr>These are advanced options to determine the configuration of the simulated "
|
||||
"console.<br><br>Mouse over an option for additional information."));
|
||||
"console.<br><br>Mouse over an option for additional information, and Shift+Wheel to scroll this panel."));
|
||||
addWidget(m_debug_settings = new DebugSettingsWidget(this, m_ui.settingsContainer), tr("Debug"),
|
||||
QStringLiteral("heart-monitor-line"),
|
||||
QStringLiteral("debugger-line"),
|
||||
tr("<strong>Debug Settings</strong><hr>These are options which can be used to log internal information about the application. "
|
||||
"<strong>Do not modify unless you know what you are doing</strong>, it will cause significant slowdown, and can waste large "
|
||||
"amounts of disk space."));
|
||||
@@ -399,10 +402,38 @@ bool SettingsWindow::eventFilter(QObject* object, QEvent* event)
|
||||
m_ui.helpText->setText(m_category_help_text[m_ui.settingsCategory->currentRow()]);
|
||||
}
|
||||
}
|
||||
else if (event->type() == QEvent::Wheel)
|
||||
{
|
||||
if (handleWheelEvent(static_cast<QWheelEvent*>(event)))
|
||||
return true;
|
||||
}
|
||||
|
||||
return QWidget::eventFilter(object, event);
|
||||
}
|
||||
|
||||
bool SettingsWindow::handleWheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if (!(event->modifiers() & Qt::ShiftModifier))
|
||||
return false;
|
||||
|
||||
const int amount = event->hasPixelDelta() ? event->pixelDelta().y() : (event->angleDelta().y() / 20);
|
||||
|
||||
QScrollBar* sb = m_ui.helpText->verticalScrollBar();
|
||||
if (!sb)
|
||||
return false;
|
||||
|
||||
sb->setSliderPosition(std::max(sb->sliderPosition() - amount, 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
void SettingsWindow::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if (handleWheelEvent(event))
|
||||
return;
|
||||
|
||||
QWidget::wheelEvent(event);
|
||||
}
|
||||
|
||||
void SettingsWindow::setWindowTitle(const QString& title)
|
||||
{
|
||||
if (m_filename.isEmpty())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#pragma once
|
||||
@@ -9,12 +9,14 @@
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
class QWheelEvent;
|
||||
|
||||
class INISettingsInterface;
|
||||
class SettingsInterface;
|
||||
|
||||
namespace GameList
|
||||
{
|
||||
struct Entry;
|
||||
struct Entry;
|
||||
}
|
||||
|
||||
class InterfaceSettingsWidget;
|
||||
@@ -103,6 +105,7 @@ private Q_SLOTS:
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent*) override;
|
||||
void wheelEvent(QWheelEvent* event) override;
|
||||
|
||||
private:
|
||||
enum : u32
|
||||
@@ -113,6 +116,7 @@ private:
|
||||
void setupUi(const GameList::Entry* game);
|
||||
|
||||
void addWidget(QWidget* widget, QString title, QString icon, QString help_text);
|
||||
bool handleWheelEvent(QWheelEvent* event);
|
||||
|
||||
SettingsWindow* reopen();
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<enum>Qt::TextBrowserInteraction</enum>
|
||||
<set>Qt::TextBrowserInteraction</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -233,6 +233,12 @@
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextBrowserInteraction</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -344,6 +350,12 @@
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextBrowserInteraction</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
||||
@@ -43,7 +43,7 @@ QTableWidgetItem* InputRecordingViewer::createRowItem(std::tuple<bool, u8> butto
|
||||
|
||||
void InputRecordingViewer::loadTable()
|
||||
{
|
||||
static const auto headers = QStringList({tr("Left Analog"), tr("Right Analog"), tr("Cross"), tr("Square"), tr("Triangle"), tr("Circle"), tr("L1"), tr("R1"), tr("L2"), tr("R2"), tr("D-Pad Down"), tr("D-Pad Right️"), tr("D-Pad Up️"), tr("D-Pad Left️"), tr("L3"), tr("R3"), tr("Select"), tr("Start")});
|
||||
static const auto headers = QStringList({tr("Left Analog"), tr("Right Analog"), tr("Cross"), tr("Square"), tr("Triangle"), tr("Circle"), tr("L1"), tr("R1"), tr("L2"), tr("R2"), tr("D-Pad Down"), tr("D-Pad Right"), tr("D-Pad Up"), tr("D-Pad Left"), tr("L3"), tr("R3"), tr("Select"), tr("Start")});
|
||||
m_ui.tableWidget->setColumnCount(headers.length());
|
||||
m_ui.tableWidget->setHorizontalHeaderLabels(headers);
|
||||
|
||||
@@ -111,4 +111,4 @@ void InputRecordingViewer::closeFile()
|
||||
}
|
||||
} // TODO else error
|
||||
m_ui.actionClose->setEnabled(m_file_open);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
+4241
-3411
File diff suppressed because it is too large
Load Diff
+3986
-3157
File diff suppressed because it is too large
Load Diff
+3979
-3149
File diff suppressed because it is too large
Load Diff
+4172
-3342
File diff suppressed because it is too large
Load Diff
+4002
-3172
File diff suppressed because it is too large
Load Diff
+3987
-3157
File diff suppressed because it is too large
Load Diff
+3980
-3150
File diff suppressed because it is too large
Load Diff
+2597
-2416
File diff suppressed because it is too large
Load Diff
+3980
-3150
File diff suppressed because it is too large
Load Diff
+3993
-3164
File diff suppressed because it is too large
Load Diff
+5492
-4662
File diff suppressed because it is too large
Load Diff
+5581
-4753
File diff suppressed because it is too large
Load Diff
+4163
-3334
File diff suppressed because it is too large
Load Diff
+4017
-3187
File diff suppressed because it is too large
Load Diff
+3979
-3149
File diff suppressed because it is too large
Load Diff
+3994
-3164
File diff suppressed because it is too large
Load Diff
+3980
-3150
File diff suppressed because it is too large
Load Diff
+4055
-3225
File diff suppressed because it is too large
Load Diff
+3977
-3146
File diff suppressed because it is too large
Load Diff
+4016
-3187
File diff suppressed because it is too large
Load Diff
+3981
-3153
File diff suppressed because it is too large
Load Diff
+4049
-3219
File diff suppressed because it is too large
Load Diff
+3979
-3149
File diff suppressed because it is too large
Load Diff
+4128
-3298
File diff suppressed because it is too large
Load Diff
+3981
-3149
File diff suppressed because it is too large
Load Diff
+4094
-3264
File diff suppressed because it is too large
Load Diff
+4027
-3197
File diff suppressed because it is too large
Load Diff
+3981
-3149
File diff suppressed because it is too large
Load Diff
+3979
-3149
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user