Compare commits

...

10 Commits

Author SHA1 Message Date
chaoticgd cafe7a9dc2 Debugger: Improve error handling in getIOPThreads and getIOPModules 2025-07-08 22:02:54 +02:00
chaoticgd 7ffc671c3a Memcard: Remove a buggy assertion 2025-07-08 21:27:17 +02:00
JordanTheToaster eaeea83547 GraphicsSettingsWidget: Correctly set current index 2025-07-08 11:32:53 +02:00
SternXD 76b758dbd2 OSD/Achievements: Add 9-position alignment options for Achievement notifications/popups, and OSD 2025-07-08 10:35:40 +02:00
Haisom ab19b109ce Core/Qt: Add hotkey support for swapping memory card
### Description of Changes

- Adds Swap Memory Card function.
- Adds Helper Function to verify whenever memory cards are auto-ejecting.
- Adds assert to make sure the memory cards swapping function will only RunOnCPUThreat.
- Adds field to set a custom hotkey under Controllers>Hotkeys to quickly swap memory cards.

### Rationale behind Changes

- Allow users to change memory cards on demand. This is really useful on shared machines, specially with kids around (Forget kids accidentally overwriting your save games with over 100 hours of gameplay!).
- This will easy up process for saving on backup memory cards on the fly without the need of auxiliary tools such as "mymc".
- By creating a memory card swap function in the core, we can now use it anywhere.

### Suggested Testing Steps

- Assign hotkey under Controllers>Hotkeys>Swap Memory Cards and test while on BIOS Browser or in game.

Special thanks to @kamfretoz  @RedDevilus , @RedPanda4552 , and @Mrlinkwii  for the feedback, suggestions and troubleshooting!

Co-Authored-By: pandubz <redpanda4552@gmail.com>
Co-Authored-By: KamFretoZ <14798312+kamfretoz@users.noreply.github.com>
2025-07-08 10:34:59 +02:00
RedDevilus 73c3216ca6 Qt: Group OSD Checkboxes
Done some preliminary work on grouping all the OSD checkboxes including the new ones in a better to glance 3 column viewscreen.

Split from https://github.com/PCSX2/pcsx2/pull/12642 which had system time and date on top
2025-07-08 10:33:50 +02:00
PCSX2 Bot ee56c5b13c [ci skip] PAD: Update to latest controller database. 2025-07-07 18:02:05 +02:00
chaoticgd 46768c8624 Debugger: Allow default layouts to be defined with different groups 2025-07-07 17:57:24 +02:00
chaoticgd 24340caa35 Debugger: Update symbol tree license headers 2025-07-07 15:43:59 +02:00
nassau-tk 6dc92b00a6 GameDB: Update JP names for Tom Clancy's Splinter Cell.
SLPM-66672, SLPM-66868.
2025-07-06 18:44:49 +02:00
32 changed files with 1073 additions and 187 deletions
+4 -4
View File
@@ -49994,8 +49994,8 @@ SLPM-66671:
gameFixes:
- DMABusyHack
SLPM-66672:
name: "スプリンターセル 二重スパイ"
name-sort: "すぷりんたーせる にじゅうすぱい"
name: "トム・クランシーシリーズ スプリンターセル 二重スパイ"
name-sort: "とむくらんしーしりーず すぷりんたーせる にじゅうすぱい"
name-en: "Tom Clancy's Splinter Cell - Double Agent"
region: "NTSC-J"
gsHWFixes:
@@ -51193,8 +51193,8 @@ SLPM-66867:
name-en: "MotoGP '07"
region: "NTSC-J"
SLPM-66868:
name: "スプリンターセル 二重スパイ [UBISOFT BEST]"
name-sort: "すぷりんたーせる にじゅうすぱい [UBISOFT BEST]"
name: "トム・クランシーシリーズ スプリンターセル 二重スパイ [UBISOFT BEST]"
name-sort: "とむくらんしーしりーず すぷりんたーせる にじゅうすぱい [UBISOFT BEST]"
name-en: "Tom Clancy's Splinter Cell - Double Agent [Ubisoft Best]"
region: "NTSC-J"
gsHWFixes:
+7 -1
View File
@@ -112,6 +112,7 @@
03000000020500000913000000000000,Anbernic RG P01,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:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000373500000710000000000000,Anbernic RG P01,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000373500004610000000000000,Anbernic RG P01,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,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000190e00000110000000000000,Aquaplus Piece,a:b1,b:b0,back:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b2,platform:Windows,
03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,platform:Windows,
03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Windows,
03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
@@ -232,6 +233,7 @@
03000000ac0500002d02000000000000,GameSir G4,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:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000ac0500004d04000000000000,GameSir G4,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000ac0500001a06000000000000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000373500009410000000000000,GameSir Tegenaria Lite,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
0300000047530000616d000000000000,GameStop,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:Windows,
@@ -340,6 +342,7 @@
03000000242f00000a20000000000000,Hyperkin Scout,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,
03000000242e00000a20000000000000,Hyperkin Scout Premium SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,
03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Windows,
03000000f00300008d04000000000000,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:-a2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:+a5,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,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,
03000000d81d00001000000000000000,iBuffalo BSGP1204P 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,
@@ -1236,6 +1239,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000020500000913000010010000,Anbernic RG P01,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,
03000000373500000710000010010000,Anbernic RG P01,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,
05000000373500004610000001000000,Anbernic RG P01,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,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000190e00000110000010010000,Aquaplus Piece,a:b1,b:b0,back:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b2,platform:Linux,
03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
@@ -1305,6 +1309,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000373500009710000001020000,GameSir Kaleid Flux,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,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000ac0500001a06000011010000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,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,
03000000bc2000005656000011010000,GameSir T4w,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,
03000000373500009410000010010000,GameSir Tegenaria Lite,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,
0500000047532047616d657061640000,GameStop Gamepad,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:Linux,
030000006f0e00000104000000010000,Gamestop Logic3 Controller,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,
030000008f0e00000800000010010000,Gasia PlayStation Gamepad,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,
@@ -1501,7 +1506,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux,
05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
050000005a1d00000218000003000000,Nokia GC 5000,a:b9,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,
050000005a1d00000218000003000000,Nokia GC 5000,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,
030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
030000007e0500007320000011010000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Linux,
030000007e0500001920000011810000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,platform:Linux,
@@ -1824,4 +1829,5 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
xinput,XInput Controller,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,
03000000120c0000100e000011010000,Zeroplus P4,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,
03000000120c0000101e000011010000,Zeroplus P4,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,
03000000120c0000182e000011010000,Zeroplus 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,
+6 -7
View File
@@ -872,8 +872,7 @@ void DockLayout::setupDefaultLayout()
for (const DockTables::DefaultDockWidgetDescription& dock_description : base_layout->widgets)
{
const DockTables::DefaultDockGroupDescription& group =
base_layout->groups[static_cast<u32>(dock_description.group)];
const DockTables::DefaultDockGroupDescription& group = base_layout->groups.at(dock_description.group);
DebuggerView* widget = nullptr;
for (auto& [unique_name, test_widget] : m_widgets)
@@ -887,19 +886,19 @@ void DockLayout::setupDefaultLayout()
KDDockWidgets::Config::self().viewFactory()->createDockWidget(widget->uniqueName()));
view->setWidget(widget);
if (!groups[static_cast<u32>(dock_description.group)])
if (!groups.at(dock_description.group))
{
KDDockWidgets::QtWidgets::DockWidget* parent = nullptr;
if (group.parent != DockTables::DefaultDockGroup::ROOT)
parent = groups[static_cast<u32>(group.parent)];
if (group.parent >= 0 && group.parent < static_cast<s32>(groups.size()))
parent = groups.at(group.parent);
g_debugger_window->addDockWidget(view, group.location, parent);
groups[static_cast<u32>(dock_description.group)] = view;
groups.at(dock_description.group) = view;
}
else
{
groups[static_cast<u32>(dock_description.group)]->addDockWidgetAsTab(view);
groups.at(dock_description.group)->addDockWidgetAsTab(view);
}
}
+1 -1
View File
@@ -45,12 +45,12 @@ const std::map<std::string, DockTables::DebuggerViewDescription> DockTables::DEB
DEBUGGER_VIEW(LocalVariableTreeView, QT_TRANSLATE_NOOP("DebuggerView", "Locals"), BOTTOM_MIDDLE),
DEBUGGER_VIEW(MemorySearchView, QT_TRANSLATE_NOOP("DebuggerView", "Memory Search"), TOP_LEFT),
DEBUGGER_VIEW(MemoryView, QT_TRANSLATE_NOOP("DebuggerView", "Memory"), BOTTOM_MIDDLE),
DEBUGGER_VIEW(ModuleView, QT_TRANSLATE_NOOP("DebuggerView", "Modules"), BOTTOM_MIDDLE),
DEBUGGER_VIEW(ParameterVariableTreeView, QT_TRANSLATE_NOOP("DebuggerView", "Parameters"), BOTTOM_MIDDLE),
DEBUGGER_VIEW(RegisterView, QT_TRANSLATE_NOOP("DebuggerView", "Registers"), TOP_LEFT),
DEBUGGER_VIEW(SavedAddressesView, QT_TRANSLATE_NOOP("DebuggerView", "Saved Addresses"), BOTTOM_MIDDLE),
DEBUGGER_VIEW(StackView, QT_TRANSLATE_NOOP("DebuggerView", "Stack"), BOTTOM_MIDDLE),
DEBUGGER_VIEW(ThreadView, QT_TRANSLATE_NOOP("DebuggerView", "Threads"), BOTTOM_MIDDLE),
DEBUGGER_VIEW(ModuleView, QT_TRANSLATE_NOOP("DebuggerView", "Modules"), BOTTOM_MIDDLE),
};
#undef DEBUGGER_VIEW
+13 -8
View File
@@ -30,18 +30,23 @@ namespace DockTables
extern const std::map<std::string, DebuggerViewDescription> DEBUGGER_VIEWS;
enum class DefaultDockGroup
using DockGroup = s32;
namespace DefaultDockGroup
{
ROOT = -1,
TOP_RIGHT = 0,
BOTTOM = 1,
TOP_LEFT = 2
};
enum
{
ROOT = -1,
TOP_RIGHT = 0,
BOTTOM = 1,
TOP_LEFT = 2
};
}
struct DefaultDockGroupDescription
{
KDDockWidgets::Location location;
DefaultDockGroup parent;
DockGroup parent;
};
extern const std::vector<DefaultDockGroupDescription> DEFAULT_DOCK_GROUPS;
@@ -49,7 +54,7 @@ namespace DockTables
struct DefaultDockWidgetDescription
{
std::string type;
DefaultDockGroup group;
DockGroup group;
};
struct DefaultDockLayout
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
// SPDX-License-Identifier: GPL-3.0+
#include "SymbolTreeDelegates.h"
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
// SPDX-License-Identifier: GPL-3.0+
#pragma once
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
// SPDX-License-Identifier: GPL-3.0+
#include "SymbolTreeLocation.h"
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
// SPDX-License-Identifier: GPL-3.0+
#pragma once
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
// SPDX-License-Identifier: GPL-3.0+
#include "SymbolTreeModel.h"
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
// SPDX-License-Identifier: GPL-3.0+
#pragma once
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
// SPDX-License-Identifier: GPL-3.0+
#include "SymbolTreeNode.h"
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
// SPDX-License-Identifier: GPL-3.0+
#pragma once
+1 -1
View File
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
// SPDX-License-Identifier: GPL-3.0+
#include "TypeString.h"
+1 -1
View File
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
// SPDX-License-Identifier: GPL-3.0+
#pragma once
@@ -9,6 +9,7 @@
#include "QtUtils.h"
#include "pcsx2/Achievements.h"
#include "pcsx2/Config.h"
#include "pcsx2/Host.h"
#include "common/StringUtil.h"
@@ -35,6 +36,8 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unlockSound, "Achievements", "UnlockSound", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.lbSound, "Achievements", "LBSubmitSound", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.overlays, "Achievements", "Overlays", true);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.overlayPosition, "Achievements", "OverlayPosition", static_cast<int>(AchievementOverlayPosition::BottomRight));
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.notificationPosition, "Achievements", "NotificationPosition", static_cast<int>(OsdOverlayPos::TopLeft));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.encoreMode, "Achievements", "EncoreMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.spectatorMode, "Achievements", "SpectatorMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unofficialAchievements, "Achievements", "UnofficialTestMode",false);
@@ -52,6 +55,8 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi
dialog->registerWidgetHelp(m_ui.soundEffects, tr("Enable Sound Effects"), tr("Checked"), tr("Plays sound effects for events such as achievement unlocks and leaderboard submissions."));
dialog->registerWidgetHelp(m_ui.soundEffectsBox, tr("Custom Sound Effect"), tr("Any"), tr("Customize the sound effect that are played whenever you received a notification, earned an achievement or submitted an entry to the leaderboard."));
dialog->registerWidgetHelp(m_ui.overlays, tr("Enable In-Game Overlays"), tr("Checked"), tr("Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active."));
dialog->registerWidgetHelp(m_ui.overlayPosition, tr("Overlay Position"), tr("Bottom Right"), tr("Determines where achievement overlays are positioned on the screen."));
dialog->registerWidgetHelp(m_ui.notificationPosition, tr("Notification Position"), tr("Top Left"), tr("Determines where achievement notification popups are positioned on the screen."));
dialog->registerWidgetHelp(m_ui.encoreMode, tr("Enable Encore Mode"), tr("Unchecked"),tr("When enabled, each session will behave as if no achievements have been unlocked."));
dialog->registerWidgetHelp(m_ui.spectatorMode, tr("Enable Spectator Mode"), tr("Unchecked"), tr("When enabled, PCSX2 will assume all achievements are locked and not send any unlock notifications to the server."));
dialog->registerWidgetHelp(m_ui.unofficialAchievements, tr("Test Unofficial Achievements"), tr("Unchecked"), tr("When enabled, PCSX2 will list achievements from unofficial sets. Please note that these achievements are not tracked by RetroAchievements, so they unlock every time."));
@@ -65,6 +70,7 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi
connect(m_ui.notificationSound, &QCheckBox::checkStateChanged, this, &AchievementSettingsWidget::updateEnableState);
connect(m_ui.unlockSound, &QCheckBox::checkStateChanged, this, &AchievementSettingsWidget::updateEnableState);
connect(m_ui.lbSound, &QCheckBox::checkStateChanged, this, &AchievementSettingsWidget::updateEnableState);
connect(m_ui.overlays, &QCheckBox::checkStateChanged, this, &AchievementSettingsWidget::updateEnableState);
connect(m_ui.achievementNotificationsDuration, &QSlider::valueChanged, this, &AchievementSettingsWidget::onAchievementsNotificationDurationSliderChanged);
connect(m_ui.leaderboardNotificationsDuration, &QSlider::valueChanged, this, &AchievementSettingsWidget::onLeaderboardsNotificationDurationSliderChanged);
@@ -139,6 +145,16 @@ void AchievementSettingsWidget::updateEnableState()
m_ui.soundEffects->setEnabled(enabled);
m_ui.overlays->setEnabled(enabled);
const bool overlays_enabled = enabled && m_dialog->getEffectiveBoolValue("Achievements", "Overlays", true);
const bool notifications_enabled = enabled && (m_dialog->getEffectiveBoolValue("Achievements", "Notifications", true) ||
m_dialog->getEffectiveBoolValue("Achievements", "LeaderboardNotifications", true));
m_ui.overlaySettingsBox->setEnabled(overlays_enabled || notifications_enabled);
m_ui.overlayPosition->setEnabled(overlays_enabled);
m_ui.overlayPositionLabel->setEnabled(overlays_enabled);
m_ui.notificationPosition->setEnabled(notifications_enabled);
m_ui.notificationPositionLabel->setEnabled(notifications_enabled);
m_ui.encoreMode->setEnabled(enabled);
m_ui.spectatorMode->setEnabled(enabled);
m_ui.unofficialAchievements->setEnabled(enabled);
@@ -197,6 +197,133 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="overlaySettingsBox">
<property name="title">
<string>Overlay Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_overlay">
<item row="0" column="0">
<widget class="QLabel" name="overlayPositionLabel">
<property name="text">
<string>Overlay Position:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="overlayPosition">
<item>
<property name="text">
<string>Top Left</string>
</property>
</item>
<item>
<property name="text">
<string>Top Center</string>
</property>
</item>
<item>
<property name="text">
<string>Top Right</string>
</property>
</item>
<item>
<property name="text">
<string>Center Left</string>
</property>
</item>
<item>
<property name="text">
<string>Center</string>
</property>
</item>
<item>
<property name="text">
<string>Center Right</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Left</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Center</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Right (Default)</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="notificationPositionLabel">
<property name="text">
<string>Notification Position:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="notificationPosition">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Top Left (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Top Center</string>
</property>
</item>
<item>
<property name="text">
<string>Top Right</string>
</property>
</item>
<item>
<property name="text">
<string>Center Left</string>
</property>
</item>
<item>
<property name="text">
<string>Center</string>
</property>
</item>
<item>
<property name="text">
<string>Center Right</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Left</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Center</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Right</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="soundEffectsBox">
<property name="title">
+254 -104
View File
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>720</width>
<height>594</height>
<height>656</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@@ -663,7 +663,7 @@
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LayoutDirection::LeftToRight</enum>
<enum>Qt::LeftToRight</enum>
</property>
<item>
<property name="text">
@@ -1315,7 +1315,7 @@
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@@ -1471,7 +1471,7 @@
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@@ -1540,7 +1540,7 @@
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@@ -1562,7 +1562,14 @@
<property name="title">
<string>On-Screen Display</string>
</property>
<layout class="QFormLayout" name="formLayout_8">
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<widget class="QLabel" name="osdPerformancePosLabel">
<property name="text">
<string>OSD Performance Position:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="osdScaleLabel">
<property name="text">
@@ -1572,6 +1579,12 @@
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="osdScale">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="suffix">
<string>%</string>
</property>
@@ -1599,21 +1612,49 @@
</item>
<item>
<property name="text">
<string>Left (Default)</string>
<string>Top Left (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Right</string>
<string>Top Center</string>
</property>
</item>
<item>
<property name="text">
<string>Top Right</string>
</property>
</item>
<item>
<property name="text">
<string>Center Left</string>
</property>
</item>
<item>
<property name="text">
<string>Center</string>
</property>
</item>
<item>
<property name="text">
<string>Center Right</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Left</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Center</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Right</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="osdPerformancePosLabel">
<property name="text">
<string>OSD Performance Position:</string>
</property>
</widget>
</item>
<item row="2" column="1">
@@ -1625,144 +1666,253 @@
</item>
<item>
<property name="text">
<string>Left</string>
<string>Top Left</string>
</property>
</item>
<item>
<property name="text">
<string>Right (Default)</string>
<string>Top Center</string>
</property>
</item>
<item>
<property name="text">
<string>Top Right (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Center Left</string>
</property>
</item>
<item>
<property name="text">
<string>Center</string>
</property>
</item>
<item>
<property name="text">
<string>Center Right</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Left</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Center</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Right</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0" colspan="2">
<layout class="QGridLayout" name="osdOptionLayout">
<item row="2" column="1">
<widget class="QCheckBox" name="osdShowSpeed">
<property name="text">
<string>Show Speed Percentages</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="osdShowVideoCapture">
<property name="text">
<string>Show Video Capture Status</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="osdShowInputRec">
<property name="text">
<string>Show Input Recording Status</string>
</property>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0" colspan="2">
<layout class="QGridLayout" name="osdOptionLayout" rowstretch="0,0,0,0,0,0,0,0,0,0,0">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="spacing">
<number>7</number>
</property>
<item row="1" column="2">
<widget class="QCheckBox" name="osdShowIndicators">
<property name="text">
<string>Show Indicators</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="2" column="0">
<widget class="QCheckBox" name="osdShowFPS">
<property name="text">
<string>Show FPS</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="osdShowVPS">
<property name="text">
<string>Show VPS</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="osdShowInputs">
<property name="text">
<string>Show Inputs</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="osdShowHardwareInfo">
<property name="text">
<string>Show Hardware Info</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="osdShowGPU">
<property name="text">
<string>Show GPU Usage</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="osdShowCPU">
<property name="text">
<string>Show CPU Usage</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="2" column="2">
<widget class="QCheckBox" name="osdShowSettings">
<property name="text">
<string>Show Settings</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="osdShowFrameTimes">
<item row="4" column="2">
<widget class="QCheckBox" name="osdShowInputs">
<property name="text">
<string>Show Frame Times</string>
<string>Show Inputs</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="osdShowResolution">
<item row="1" column="0">
<widget class="QCheckBox" name="osdShowSpeed">
<property name="text">
<string>Show Resolution</string>
<string>Show Speed Percentages</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="osdShowGSStats">
<property name="text">
<string>Show Statistics</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="osdShowVersion">
<property name="text">
<string>Show PCSX2 Version</string>
</property>
</widget>
</item>
<item row="8" column="1">
<item row="10" column="2">
<widget class="QCheckBox" name="warnAboutUnsafeSettings">
<property name="text">
<string>Warn About Unsafe Settings</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QCheckBox" name="osdShowVideoCapture">
<property name="text">
<string>Show Video Capture Status</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QCheckBox" name="osdShowGPU">
<property name="text">
<string>Show GPU Usage</string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QCheckBox" name="osdShowInputRec">
<property name="text">
<string>Show Input Recording Status</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="Column1_SystemInformation">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>System Information</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="Column0_PerformanceAndStats">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Performance &amp; Stats</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="Column2_SettingsAndInputs">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Settings &amp; Inputs</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="osdShowGSStats">
<property name="text">
<string>Show Statistics</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="osdShowCPU">
<property name="text">
<string>Show CPU Usage</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="osdShowVPS">
<property name="text">
<string>Show VPS</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="osdShowResolution">
<property name="text">
<string>Show Resolution</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="osdShowFrameTimes">
<property name="text">
<string>Show Frame Times</string>
</property>
</widget>
</item>
<item row="9" column="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Warnings For User</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="osdShowHardwareInfo">
<property name="text">
<string>Show Hardware Info</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="osdShowVersion">
<property name="text">
<string>Show PCSX2 Version</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>20</height>
</size>
</property>
</spacer>
@@ -2049,7 +2199,7 @@
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@@ -2293,7 +2443,7 @@
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@@ -2310,7 +2460,7 @@
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
+219 -11
View File
@@ -164,6 +164,7 @@ namespace Achievements
static void DisplayHardcoreDeferredMessage();
static void DisplayAchievementSummary();
static void UpdateRichPresence(std::unique_lock<std::recursive_mutex>& lock);
static void UpdateNotificationPosition();
static std::string GetAchievementBadgePath(const rc_client_achievement_t* achievement, int state);
static std::string GetUserBadgePath(const std::string_view username);
@@ -444,6 +445,9 @@ bool Achievements::Initialize()
if (VMManager::HasValidVM() && IsLoggedInOrLoggingIn() && EmuConfig.Achievements.HardcoreMode)
DisplayHardcoreDeferredMessage();
// Set initial notification position
UpdateNotificationPosition();
return true;
}
@@ -494,6 +498,63 @@ void Achievements::DestroyClient(rc_client_t** client, std::unique_ptr<HTTPDownl
http->reset();
}
void Achievements::UpdateNotificationPosition()
{
// Set notification position based on achievement settings
float horizontal_position, vertical_position, direction;
// Determine horizontal alignment
switch (EmuConfig.Achievements.NotificationPosition)
{
case OsdOverlayPos::TopLeft:
case OsdOverlayPos::CenterLeft:
case OsdOverlayPos::BottomLeft:
horizontal_position = 0.0f; // Left
break;
case OsdOverlayPos::TopCenter:
case OsdOverlayPos::Center:
case OsdOverlayPos::BottomCenter:
horizontal_position = 0.5f; // Center
break;
case OsdOverlayPos::TopRight:
case OsdOverlayPos::CenterRight:
case OsdOverlayPos::BottomRight:
default:
horizontal_position = 1.0f; // Right
break;
}
// Determine vertical alignment and stacking direction
switch (EmuConfig.Achievements.NotificationPosition)
{
case OsdOverlayPos::TopLeft:
case OsdOverlayPos::TopCenter:
case OsdOverlayPos::TopRight:
vertical_position = 0.15f; // Top area
direction = 1.0f; // Stack downward
break;
case OsdOverlayPos::CenterLeft:
case OsdOverlayPos::Center:
case OsdOverlayPos::CenterRight:
vertical_position = 0.5f; // Center
direction = 1.0f; // Stack downward
break;
case OsdOverlayPos::BottomLeft:
case OsdOverlayPos::BottomCenter:
case OsdOverlayPos::BottomRight:
default:
vertical_position = 0.85f; // Bottom area
direction = -1.0f; // Stack upward
break;
}
ImGuiFullscreen::SetNotificationPosition(horizontal_position, vertical_position, direction);
}
void Achievements::UpdateSettings(const Pcsx2Config::AchievementsOptions& old_config)
{
if (IsUsingRAIntegration())
@@ -549,6 +610,10 @@ void Achievements::UpdateSettings(const Pcsx2Config::AchievementsOptions& old_co
rc_client_set_unofficial_enabled(s_client, EmuConfig.Achievements.UnofficialTestMode);
}
// Update notification position if it changed
if (EmuConfig.Achievements.NotificationPosition != old_config.NotificationPosition)
UpdateNotificationPosition();
// in case cache directory changed
EnsureCacheDirectoriesExist();
}
@@ -1915,6 +1980,115 @@ static float IndicatorOpacity(const T& i)
return (i.active) ? opacity : (1.0f - opacity);
}
static ImVec2 CalculateOverlayPosition(const ImGuiIO& io, float padding, AchievementOverlayPosition alignment)
{
switch (alignment)
{
case AchievementOverlayPosition::TopLeft:
return ImVec2(padding, padding);
case AchievementOverlayPosition::TopCenter:
return ImVec2(io.DisplaySize.x * 0.5f, padding);
case AchievementOverlayPosition::TopRight:
return ImVec2(io.DisplaySize.x - padding, padding);
case AchievementOverlayPosition::CenterLeft:
return ImVec2(padding, io.DisplaySize.y * 0.5f);
case AchievementOverlayPosition::Center:
return ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f);
case AchievementOverlayPosition::CenterRight:
return ImVec2(io.DisplaySize.x - padding, io.DisplaySize.y * 0.5f);
case AchievementOverlayPosition::BottomLeft:
return ImVec2(padding, io.DisplaySize.y - padding);
case AchievementOverlayPosition::BottomCenter:
return ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y - padding);
case AchievementOverlayPosition::BottomRight:
default:
return ImVec2(io.DisplaySize.x - padding, io.DisplaySize.y - padding);
}
}
static ImVec2 AdjustPositionForAlignment(const ImVec2& base_position, const ImVec2& element_size, AchievementOverlayPosition alignment)
{
ImVec2 adjusted = base_position;
// Adjust for horizontal alignment
switch (alignment)
{
case AchievementOverlayPosition::TopLeft:
case AchievementOverlayPosition::CenterLeft:
case AchievementOverlayPosition::BottomLeft:
// Left aligned no adjustment needed for x
break;
case AchievementOverlayPosition::TopCenter:
case AchievementOverlayPosition::Center:
case AchievementOverlayPosition::BottomCenter:
// Center aligned offset by half element width
adjusted.x -= element_size.x * 0.5f;
break;
case AchievementOverlayPosition::TopRight:
case AchievementOverlayPosition::CenterRight:
case AchievementOverlayPosition::BottomRight:
default:
// Right aligned offset by full element width
adjusted.x -= element_size.x;
break;
}
// Adjust for vertical alignment
switch (alignment)
{
case AchievementOverlayPosition::TopLeft:
case AchievementOverlayPosition::TopCenter:
case AchievementOverlayPosition::TopRight:
// Top aligned no adjustment needed for y
break;
case AchievementOverlayPosition::CenterLeft:
case AchievementOverlayPosition::Center:
case AchievementOverlayPosition::CenterRight:
// Center aligned offset by half element height
adjusted.y -= element_size.y * 0.5f;
break;
case AchievementOverlayPosition::BottomLeft:
case AchievementOverlayPosition::BottomCenter:
case AchievementOverlayPosition::BottomRight:
default:
// Bottom aligned offset by full element height
adjusted.y -= element_size.y;
break;
}
return adjusted;
}
static ImVec2 GetStackingDirection(AchievementOverlayPosition alignment)
{
switch (alignment)
{
case AchievementOverlayPosition::TopLeft:
case AchievementOverlayPosition::TopCenter:
case AchievementOverlayPosition::TopRight:
return ImVec2(0.0f, 1.0f); // Stack downward
case AchievementOverlayPosition::BottomLeft:
case AchievementOverlayPosition::BottomCenter:
case AchievementOverlayPosition::BottomRight:
default:
return ImVec2(0.0f, -1.0f); // Stack upward
case AchievementOverlayPosition::CenterLeft:
return ImVec2(1.0f, 0.0f); // Stack rightward
case AchievementOverlayPosition::CenterRight:
return ImVec2(-1.0f, 0.0f); // Stack leftward
case AchievementOverlayPosition::Center:
return ImVec2(0.0f, -1.0f); // Stack upward for center
}
}
void Achievements::DrawGameOverlays()
{
@@ -1930,13 +2104,14 @@ void Achievements::DrawGameOverlays()
const float padding = LayoutScale(10.0f);
const ImVec2 image_size = LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT);
const ImGuiIO& io = ImGui::GetIO();
ImVec2 position = ImVec2(io.DisplaySize.x - padding, io.DisplaySize.y - padding);
ImVec2 position = CalculateOverlayPosition(io, padding, EmuConfig.Achievements.OverlayPosition);
ImDrawList* dl = ImGui::GetBackgroundDrawList();
if (!s_active_challenge_indicators.empty())
{
const ImVec2 stack_direction = GetStackingDirection(EmuConfig.Achievements.OverlayPosition);
ImVec2 current_position = AdjustPositionForAlignment(position, image_size, EmuConfig.Achievements.OverlayPosition);
const float x_advance = image_size.x + spacing;
ImVec2 current_position = ImVec2(position.x - image_size.x, position.y - image_size.y);
for (auto it = s_active_challenge_indicators.begin(); it != s_active_challenge_indicators.end();)
{
@@ -1949,7 +2124,26 @@ void Achievements::DrawGameOverlays()
{
dl->AddImage(reinterpret_cast<ImTextureID>(badge->GetNativeHandle()),
current_position, current_position + image_size, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), col);
current_position.x -= x_advance;
// For horizontal layouts, go horizontally for vertical layouts, stay in the same row
if (std::abs(stack_direction.x) > 0.0f)
{
current_position.x += stack_direction.x * x_advance;
}
else
{
// For right-aligned vertical layouts, move left for next indicator
switch (EmuConfig.Achievements.OverlayPosition)
{
case AchievementOverlayPosition::TopRight:
case AchievementOverlayPosition::BottomRight:
current_position.x -= x_advance;
break;
default:
current_position.x += x_advance;
break;
}
}
}
if (!indicator.active && opacity <= 0.01f)
@@ -1963,7 +2157,9 @@ void Achievements::DrawGameOverlays()
}
}
position.y -= image_size.y + padding;
// Go to the next row/column for anymore overlays
position.x += stack_direction.x * (image_size.x + padding);
position.y += stack_direction.y * (image_size.y + padding);
}
if (s_active_progress_indicator.has_value())
@@ -1976,9 +2172,12 @@ void Achievements::DrawGameOverlays()
const char* text_end = text_start + std::strlen(text_start);
const ImVec2 text_size = g_medium_font->CalcTextSizeA(g_medium_font->FontSize, FLT_MAX, 0.0f, text_start, text_end);
const ImVec2 box_min =
ImVec2(position.x - image_size.x - text_size.x - spacing - padding * 2.0f, position.y - image_size.y - padding * 2.0f);
const ImVec2 box_max = position;
const ImVec2 progress_box_size = ImVec2(image_size.x + text_size.x + spacing + padding * 2.0f, image_size.y + padding * 2.0f);
const ImVec2 stack_direction = GetStackingDirection(EmuConfig.Achievements.OverlayPosition);
const ImVec2 box_position = AdjustPositionForAlignment(position, progress_box_size, EmuConfig.Achievements.OverlayPosition);
const ImVec2 box_min = box_position;
const ImVec2 box_max = box_position + progress_box_size;
const float box_rounding = LayoutScale(1.0f);
dl->AddRectFilled(box_min, box_max, ImGui::GetColorU32(ImVec4(0.13f, 0.13f, 0.13f, opacity * 0.5f)), box_rounding);
@@ -2002,11 +2201,15 @@ void Achievements::DrawGameOverlays()
s_active_progress_indicator.reset();
}
position.y -= image_size.y + padding * 3.0f;
// Go to the next row/column for anymore overlays
position.x += stack_direction.x * (progress_box_size.x + padding);
position.y += stack_direction.y * (progress_box_size.y + padding);
}
if (!s_active_leaderboard_trackers.empty())
{
const ImVec2 stack_direction = GetStackingDirection(EmuConfig.Achievements.OverlayPosition);
for (auto it = s_active_leaderboard_trackers.begin(); it != s_active_leaderboard_trackers.end();)
{
const LeaderboardTrackerIndicator& indicator = *it;
@@ -2019,8 +2222,11 @@ void Achievements::DrawGameOverlays()
const ImVec2 size = ImGuiFullscreen::g_medium_font->CalcTextSizeA(
ImGuiFullscreen::g_medium_font->FontSize, FLT_MAX, 0.0f, width_string.c_str(), width_string.end_ptr());
const ImVec2 box_min = ImVec2(position.x - size.x - padding * 2.0f, position.y - size.y - padding * 2.0f);
const ImVec2 box_max = position;
const ImVec2 tracker_box_size = ImVec2(size.x + padding * 2.0f, size.y + padding * 2.0f);
const ImVec2 box_position = AdjustPositionForAlignment(position, tracker_box_size, EmuConfig.Achievements.OverlayPosition);
const ImVec2 box_min = box_position;
const ImVec2 box_max = box_position + tracker_box_size;
const float box_rounding = LayoutScale(1.0f);
dl->AddRectFilled(box_min, box_max, ImGui::GetColorU32(ImVec4(0.13f, 0.13f, 0.13f, opacity * 0.5f)), box_rounding);
dl->AddRect(box_min, box_max, ImGui::GetColorU32(ImVec4(0.8f, 0.8f, 0.8f, opacity)), box_rounding);
@@ -2048,7 +2254,9 @@ void Achievements::DrawGameOverlays()
++it;
}
position.x = box_min.x - padding;
// Go to the next position for anymore trackers
position.x += stack_direction.x * (tracker_box_size.x + padding);
position.y += stack_direction.y * (tracker_box_size.y + padding);
}
// Uncomment if there are any other overlays above this one.
+25
View File
@@ -341,7 +341,14 @@ enum class OsdOverlayPos : u8
{
None,
TopLeft,
TopCenter,
TopRight,
CenterLeft,
Center,
CenterRight,
BottomLeft,
BottomCenter,
BottomRight,
};
enum class TexturePreloadingLevel : u8
@@ -452,6 +459,20 @@ enum class GSNativeScaling : u8
MaxCount
};
enum class AchievementOverlayPosition : u8
{
TopLeft,
TopCenter,
TopRight,
CenterLeft,
Center,
CenterRight,
BottomLeft,
BottomCenter,
BottomRight,
MaxCount
};
// --------------------------------------------------------------------------------------
// TraceLogsEE
// --------------------------------------------------------------------------------------
@@ -1213,6 +1234,8 @@ struct Pcsx2Config
static constexpr const char* DEFAULT_UNLOCK_SOUND_NAME = "sounds/achievements/unlock.wav";
static constexpr const char* DEFAULT_LBSUBMIT_SOUND_NAME = "sounds/achievements/lbsubmit.wav";
static const char* OverlayPositionNames[(size_t)AchievementOverlayPosition::MaxCount + 1];
BITFIELD32()
bool
Enabled : 1,
@@ -1231,6 +1254,8 @@ struct Pcsx2Config
u32 NotificationsDuration = DEFAULT_NOTIFICATION_DURATION;
u32 LeaderboardsDuration = DEFAULT_LEADERBOARD_DURATION;
AchievementOverlayPosition OverlayPosition = AchievementOverlayPosition::BottomRight;
OsdOverlayPos NotificationPosition = OsdOverlayPos::TopLeft;
std::string InfoSoundName;
std::string UnlockSoundName;
+15 -14
View File
@@ -4,7 +4,7 @@
#include "BiosDebugData.h"
#include "IopMem.h"
#include "Memory.h"
#include "VMManager.h"
std::vector<std::unique_ptr<BiosThread>> getEEThreads()
{
@@ -31,15 +31,18 @@ std::vector<std::unique_ptr<BiosThread>> getEEThreads()
std::vector<std::unique_ptr<BiosThread>> getIOPThreads()
{
std::vector<std::unique_ptr<BiosThread>> threads;
if (!VMManager::HasValidVM() || CurrentBiosInformation.iopThreadListAddr == 0)
return {};
if (CurrentBiosInformation.iopThreadListAddr <= 0)
return threads;
std::vector<std::unique_ptr<BiosThread>> threads;
u32 item = iopMemRead32(CurrentBiosInformation.iopThreadListAddr);
while (item != 0)
for (int i = 0; item != 0; i++)
{
if (i > 1000)
return {};
IOPInternalThread data{};
u16 tag = iopMemRead16(item + 0x8);
@@ -72,14 +75,14 @@ std::vector<std::unique_ptr<BiosThread>> getIOPThreads()
std::vector<IopMod> getIOPModules()
{
if (!VMManager::HasValidVM() || CurrentBiosInformation.iopModListAddr == 0)
return {};
u32 maddr = iopMemRead32(CurrentBiosInformation.iopModListAddr);
std::vector<IopMod> modlist;
int i = 0;
while (maddr != 0)
for (int i = 0; maddr != 0; i++)
{
IopMod mod;
if (maddr >= 0x200000)
{
// outside of memory
@@ -87,11 +90,10 @@ std::vector<IopMod> getIOPModules()
return {};
}
if (i > 200)
{
// 200 modules? unlikely
if (i > 1000)
return {};
}
IopMod mod;
u32 nstr = iopMemRead32(maddr + 4);
if (nstr)
@@ -114,7 +116,6 @@ std::vector<IopMod> getIOPModules()
modlist.push_back(mod);
maddr = iopMemRead32(maddr);
i++;
}
return modlist;
+4 -2
View File
@@ -9,6 +9,7 @@
#include "Gif_Unit.h"
#include "Host.h"
#include "ImGui/ImGuiManager.h"
#include "ImGui/ImGuiOverlays.h"
#include "R3000A.h"
#include "R5900.h"
#include "VMManager.h"
@@ -379,8 +380,9 @@ void GSDumpReplayer::RenderUI()
do \
{ \
text_size = font->CalcTextSizeA(font->FontSize, std::numeric_limits<float>::max(), -1.0f, (text), nullptr, nullptr); \
dl->AddText(font, font->FontSize, ImVec2(GSConfig.OsdPerformancePos == OsdOverlayPos::TopLeft ? ImGuiManager::GetWindowWidth() - margin - text_size.x + shadow_offset : margin + shadow_offset, position_y + shadow_offset), IM_COL32(0, 0, 0, 100), (text)); \
dl->AddText(font, font->FontSize, ImVec2(GSConfig.OsdPerformancePos == OsdOverlayPos::TopLeft ? ImGuiManager::GetWindowWidth() - margin - text_size.x : margin, position_y), color, (text)); \
const ImVec2 text_pos = CalculatePerformanceOverlayTextPosition(GSConfig.OsdPerformancePos, margin, text_size, ImGuiManager::GetWindowWidth(), position_y); \
dl->AddText(font, font->FontSize, ImVec2(text_pos.x + shadow_offset, text_pos.y + shadow_offset), IM_COL32(0, 0, 0, 100), (text)); \
dl->AddText(font, font->FontSize, text_pos, color, (text)); \
position_y += text_size.y + spacing; \
} while (0)
+6
View File
@@ -11,6 +11,7 @@
#include "Recording/InputRecording.h"
#include "SPU2/spu2.h"
#include "VMManager.h"
#include "SIO/Memcard/MemoryCardFile.h"
#include "common/Assertions.h"
#include "common/FileSystem.h"
@@ -223,6 +224,11 @@ DEFINE_HOTKEY("InputRecToggleMode", TRANSLATE_NOOP("Hotkeys", "System"),
if (!pressed && VMManager::HasValidVM())
g_InputRecording.getControls().toggleRecordMode();
})
DEFINE_HOTKEY("SwapMemCards", TRANSLATE_NOOP("Hotkeys", "System"),
TRANSLATE_NOOP("Hotkeys", "Swap Memory Cards"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
FileMcd_Swap();
})
DEFINE_HOTKEY("PreviousSaveStateSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
TRANSLATE_NOOP("Hotkeys", "Select Previous Save Slot"), [](s32 pressed) {
+52
View File
@@ -3653,6 +3653,30 @@ void FullscreenUI::DrawInterfaceSettingsPage()
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TRIANGLE_EXCLAMATION, "Warn About Unsafe Settings"),
FSUI_CSTR("Displays warnings when settings are enabled which may break games."), "EmuCore", "WarnAboutUnsafeSettings", true);
// OSD Positioning Options
static constexpr const char* s_osd_position_options[] = {
FSUI_NSTR("None"),
FSUI_NSTR("Top Left"),
FSUI_NSTR("Top Center"),
FSUI_NSTR("Top Right"),
FSUI_NSTR("Center Left"),
FSUI_NSTR("Center"),
FSUI_NSTR("Center Right"),
FSUI_NSTR("Bottom Left"),
FSUI_NSTR("Bottom Center"),
FSUI_NSTR("Bottom Right"),
};
static constexpr const char* s_osd_position_values[] = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
};
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_COMMENT, "OSD Messages Position"),
FSUI_CSTR("Determines where on-screen display messages are positioned."), "EmuCore/GS", "OsdMessagesPos", "1",
s_osd_position_options, s_osd_position_values, std::size(s_osd_position_options), true);
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_CHART_BAR, "OSD Performance Position"),
FSUI_CSTR("Determines where performance statistics are positioned."), "EmuCore/GS", "OsdPerformancePos", "3",
s_osd_position_options, s_osd_position_values, std::size(s_osd_position_options), true);
MenuHeading(FSUI_CSTR("Operations"));
if (MenuButton(FSUI_ICONSTR(ICON_FA_DUMPSTER_FIRE, "Reset Settings"),
FSUI_CSTR("Resets configuration to defaults (excluding controller settings)."), !IsEditingGameSettings(bsi)))
@@ -7598,6 +7622,34 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_HEARTBEAT_ALT, "Enable In-Game Overlays"),
FSUI_CSTR("Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active."), "Achievements",
"Overlays", true, enabled);
if (enabled)
{
const char* alignment_options[] = {
TRANSLATE_NOOP("FullscreenUI", "Top Left"),
TRANSLATE_NOOP("FullscreenUI", "Top Center"),
TRANSLATE_NOOP("FullscreenUI", "Top Right"),
TRANSLATE_NOOP("FullscreenUI", "Center Left"),
TRANSLATE_NOOP("FullscreenUI", "Center"),
TRANSLATE_NOOP("FullscreenUI", "Center Right"),
TRANSLATE_NOOP("FullscreenUI", "Bottom Left"),
TRANSLATE_NOOP("FullscreenUI", "Bottom Center"),
TRANSLATE_NOOP("FullscreenUI", "Bottom Right")
};
DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_ALIGN_CENTER, "Overlay Position"),
FSUI_CSTR("Determines where achievement overlays are positioned on the screen."), "Achievements", "OverlayPosition",
8, alignment_options, std::size(alignment_options), true, 0, enabled);
const bool notifications_enabled = Host::GetBaseBoolSettingValue("Achievements", "Notifications", true) ||
Host::GetBaseBoolSettingValue("Achievements", "LeaderboardNotifications", true);
if (notifications_enabled)
{
DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_BELL, "Notification Position"),
FSUI_CSTR("Determines where achievement notification popups are positioned on the screen."), "Achievements", "NotificationPosition",
2, alignment_options, std::size(alignment_options), true, 0, enabled);
}
}
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_LOCK, "Encore Mode"),
FSUI_CSTR("When enabled, each session will behave as if no achievements have been unlocked."), "Achievements", "EncoreMode", false,
enabled);
+29 -5
View File
@@ -181,6 +181,9 @@ namespace ImGuiFullscreen
};
static std::vector<Notification> s_notifications;
static float s_notification_vertical_position = 0.15f;
static float s_notification_vertical_direction = 1.0f;
static float s_notification_horizontal_position = 0.0f; // 0.0 = left, 0.5 = center, 1.0 = right
static std::string s_toast_title;
static std::string s_toast_message;
@@ -697,7 +700,17 @@ void ImGuiFullscreen::EndLayout()
const float notification_margin = LayoutScale(10.0f);
const float spacing = LayoutScale(10.0f);
const float notification_vertical_pos = GetNotificationVerticalPosition();
ImVec2 position(notification_margin, notification_vertical_pos * ImGui::GetIO().DisplaySize.y +
// Get the horizonal position based on alignment
float horizontal_pos;
if (s_notification_horizontal_position <= 0.0f)
horizontal_pos = notification_margin; // Left
else if (s_notification_horizontal_position >= 1.0f)
horizontal_pos = ImGui::GetIO().DisplaySize.x - notification_margin; // Right
else
horizontal_pos = ImGui::GetIO().DisplaySize.x * s_notification_horizontal_position; // Center
ImVec2 position(horizontal_pos, notification_vertical_pos * ImGui::GetIO().DisplaySize.y +
((notification_vertical_pos >= 0.5f) ? -notification_margin : notification_margin));
DrawBackgroundProgressDialogs(position, spacing);
DrawNotifications(position, spacing);
@@ -2672,9 +2685,6 @@ void ImGuiFullscreen::DrawMessageDialog()
}
}
static float s_notification_vertical_position = 0.15f;
static float s_notification_vertical_direction = 1.0f;
float ImGuiFullscreen::GetNotificationVerticalPosition()
{
return s_notification_vertical_position;
@@ -2691,6 +2701,13 @@ void ImGuiFullscreen::SetNotificationVerticalPosition(float position, float dire
s_notification_vertical_direction = direction;
}
void ImGuiFullscreen::SetNotificationPosition(float horizontal_position, float vertical_position, float direction)
{
s_notification_horizontal_position = horizontal_position;
s_notification_vertical_position = vertical_position;
s_notification_vertical_direction = direction;
}
ImGuiID ImGuiFullscreen::GetBackgroundProgressID(const char* str_id)
{
return ImHashStr(str_id);
@@ -2952,7 +2969,14 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
}
}
const ImVec2 box_min(position.x, actual_y);
// Adjust horizontal position based on alignment
float final_x = position.x;
if (s_notification_horizontal_position >= 1.0f)
final_x = position.x - box_width;
else if (s_notification_horizontal_position > 0.0f && s_notification_horizontal_position < 1.0f)
final_x = position.x - (box_width * 0.5f);
const ImVec2 box_min(final_x, actual_y);
const ImVec2 box_max(box_min.x + box_width, box_min.y + box_height);
const u32 background_color = (toast_background_color & ~IM_COL32_A_MASK) | (opacity << IM_COL32_A_SHIFT);
const u32 border_color = (toast_border_color & ~IM_COL32_A_MASK) | (opacity << IM_COL32_A_SHIFT);
+1
View File
@@ -273,6 +273,7 @@ namespace ImGuiFullscreen
float GetNotificationVerticalPosition();
float GetNotificationVerticalDirection();
void SetNotificationVerticalPosition(float position, float direction);
void SetNotificationPosition(float horizontal_position, float vertical_position, float direction);
void OpenBackgroundProgressDialog(const char* str_id, std::string message, s32 min, s32 max, s32 value);
void UpdateBackgroundProgressDialog(const char* str_id, std::string message, s32 min, s32 max, s32 value);
+51 -3
View File
@@ -730,8 +730,34 @@ void ImGuiManager::DrawOSDMessages(Common::Timer::Value current_time)
const float padding = std::ceil(8.0f * scale);
const float rounding = std::ceil(5.0f * scale);
const float max_width = s_window_width - (margin + padding) * 2.0f;
float position_x = GSConfig.OsdMessagesPos == OsdOverlayPos::TopRight ? GetWindowWidth() - margin : margin;
float position_y = margin;
switch (GSConfig.OsdMessagesPos)
{
case OsdOverlayPos::TopLeft:
case OsdOverlayPos::TopCenter:
case OsdOverlayPos::TopRight:
position_y = margin;
break;
case OsdOverlayPos::CenterLeft:
case OsdOverlayPos::Center:
case OsdOverlayPos::CenterRight:
position_y = s_window_height * 0.5f;
break;
case OsdOverlayPos::BottomLeft:
case OsdOverlayPos::BottomCenter:
case OsdOverlayPos::BottomRight:
// For bottom positions, start from the bottom and let messages stack upward
position_y = s_window_height - margin;
break;
case OsdOverlayPos::None:
default:
position_y = margin;
break;
}
auto iter = s_osd_active_messages.begin();
while (iter != s_osd_active_messages.end())
@@ -798,7 +824,18 @@ void ImGuiManager::DrawOSDMessages(Common::Timer::Value current_time)
const ImVec2 text_size(
font->CalcTextSizeA(font->FontSize, max_width, max_width, msg.text.c_str(), msg.text.c_str() + msg.text.length()));
const ImVec2 size(text_size.x + padding * 2.0f, text_size.y + padding * 2.0f);
const ImVec2 pos(position_x - (GSConfig.OsdMessagesPos == OsdOverlayPos::TopRight ? size.x : 0), actual_y);
// For bottom positions, adjust actual_y to try to account for message height
float final_y = actual_y;
if (GSConfig.OsdMessagesPos == OsdOverlayPos::BottomLeft ||
GSConfig.OsdMessagesPos == OsdOverlayPos::BottomCenter ||
GSConfig.OsdMessagesPos == OsdOverlayPos::BottomRight)
{
final_y = actual_y - size.y;
}
const ImVec2 base_pos = CalculateOSDPosition(GSConfig.OsdMessagesPos, margin, size, s_window_width, s_window_height);
const ImVec2 pos(base_pos.x, final_y);
const ImVec4 text_rect(pos.x + padding, pos.y + padding, pos.x + size.x - padding, pos.y + size.y - padding);
ImDrawList* dl = ImGui::GetBackgroundDrawList();
@@ -806,7 +843,18 @@ void ImGuiManager::DrawOSDMessages(Common::Timer::Value current_time)
dl->AddRect(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(0x48, 0x48, 0x48, opacity), rounding);
dl->AddText(font, font->FontSize, ImVec2(text_rect.x, text_rect.y), IM_COL32(0xff, 0xff, 0xff, opacity), msg.text.c_str(),
msg.text.c_str() + msg.text.length(), max_width, &text_rect);
position_y += size.y + spacing;
// Stack direction depends on the position upward for bottom positions, downward for others
if (GSConfig.OsdMessagesPos == OsdOverlayPos::BottomLeft ||
GSConfig.OsdMessagesPos == OsdOverlayPos::BottomCenter ||
GSConfig.OsdMessagesPos == OsdOverlayPos::BottomRight)
{
position_y -= (size.y + spacing); // Stack upward for bottom positions
}
else
{
position_y += size.y + spacing; // Stack downward for top/center positions
}
}
}
+148 -16
View File
@@ -49,6 +49,71 @@
InputRecordingUI::InputRecordingData g_InputRecordingData;
// OSD positioning funcs
ImVec2 CalculateOSDPosition(OsdOverlayPos position, float margin, const ImVec2& text_size, float window_width, float window_height)
{
switch (position)
{
case OsdOverlayPos::TopLeft:
return ImVec2(margin, margin);
case OsdOverlayPos::TopCenter:
return ImVec2((window_width - text_size.x) * 0.5f, margin);
case OsdOverlayPos::TopRight:
return ImVec2(window_width - margin - text_size.x, margin);
case OsdOverlayPos::CenterLeft:
return ImVec2(margin, (window_height - text_size.y) * 0.5f);
case OsdOverlayPos::Center:
return ImVec2((window_width - text_size.x) * 0.5f, (window_height - text_size.y) * 0.5f);
case OsdOverlayPos::CenterRight:
return ImVec2(window_width - margin - text_size.x, (window_height - text_size.y) * 0.5f);
case OsdOverlayPos::BottomLeft:
return ImVec2(margin, window_height - margin - text_size.y);
case OsdOverlayPos::BottomCenter:
return ImVec2((window_width - text_size.x) * 0.5f, window_height - margin - text_size.y);
case OsdOverlayPos::BottomRight:
return ImVec2(window_width - margin - text_size.x, window_height - margin - text_size.y);
case OsdOverlayPos::None:
default:
return ImVec2(0.0f, 0.0f);
}
}
ImVec2 CalculatePerformanceOverlayTextPosition(OsdOverlayPos position, float margin, const ImVec2& text_size, float window_width, float position_y)
{
const float abs_margin = std::abs(margin);
// Get the X position based on horizontal alignment
float x_pos;
switch (position)
{
case OsdOverlayPos::TopLeft:
case OsdOverlayPos::CenterLeft:
case OsdOverlayPos::BottomLeft:
x_pos = abs_margin; // Left alignment
break;
case OsdOverlayPos::TopCenter:
case OsdOverlayPos::Center:
case OsdOverlayPos::BottomCenter:
x_pos = (window_width - text_size.x) * 0.5f; // Center alignment
break;
case OsdOverlayPos::TopRight:
case OsdOverlayPos::CenterRight:
case OsdOverlayPos::BottomRight:
default:
x_pos = window_width - text_size.x - abs_margin; // Right alignment
break;
}
return ImVec2(x_pos, position_y);
}
bool ShouldUseLeftAlignment(OsdOverlayPos position)
{
return (position == OsdOverlayPos::TopLeft || position == OsdOverlayPos::CenterLeft || position == OsdOverlayPos::BottomLeft);
}
namespace ImGuiManager
{
static void FormatProcessorStat(SmallStringBase& text, double usage, double time);
@@ -107,17 +172,38 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
SmallString text;
ImVec2 text_size;
if (GSConfig.OsdPerformancePos == OsdOverlayPos::TopLeft)
margin = -margin;
// Adjust initial Y position based on vertical alignment
switch (GSConfig.OsdPerformancePos)
{
case OsdOverlayPos::CenterLeft:
case OsdOverlayPos::Center:
case OsdOverlayPos::CenterRight:
position_y = (GetWindowHeight() - (fixed_font->FontSize * 8.0f)) * 0.5f;
break;
case OsdOverlayPos::BottomLeft:
case OsdOverlayPos::BottomCenter:
case OsdOverlayPos::BottomRight:
position_y = GetWindowHeight() - margin - (fixed_font->FontSize * 15.0f + spacing * 14.0f);
break;
case OsdOverlayPos::TopLeft:
case OsdOverlayPos::TopCenter:
case OsdOverlayPos::TopRight:
default:
// Top alignment keeps the passed position_y
break;
}
#define DRAW_LINE(font, text, color) \
do \
{ \
text_size = font->CalcTextSizeA(font->FontSize, std::numeric_limits<float>::max(), -1.0f, (text), nullptr, nullptr); \
dl->AddText(font, font->FontSize, \
ImVec2((GSConfig.OsdPerformancePos == OsdOverlayPos::TopLeft ? 0 : GetWindowWidth() - text_size.x) - margin + shadow_offset, position_y + shadow_offset), \
IM_COL32(0, 0, 0, 100), (text)); \
dl->AddText(font, font->FontSize, ImVec2((GSConfig.OsdPerformancePos == OsdOverlayPos::TopLeft ? 0 : GetWindowWidth() - text_size.x) - margin, position_y), color, (text)); \
const ImVec2 text_pos = CalculatePerformanceOverlayTextPosition(GSConfig.OsdPerformancePos, margin, text_size, GetWindowWidth(), position_y); \
dl->AddText(font, font->FontSize, ImVec2(text_pos.x + shadow_offset, text_pos.y + shadow_offset), IM_COL32(0, 0, 0, 100), (text)); \
dl->AddText(font, font->FontSize, text_pos, color, (text)); \
position_y += text_size.y + spacing; \
} while (0)
@@ -299,7 +385,9 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
{
const ImVec2 history_size(200.0f * scale, 50.0f * scale);
ImGui::SetNextWindowSize(ImVec2(history_size.x, history_size.y));
ImGui::SetNextWindowPos(ImVec2((GSConfig.OsdPerformancePos == OsdOverlayPos::TopLeft ? 0 : GetWindowWidth() - history_size.x) - margin, position_y));
const ImVec2 window_pos = CalculatePerformanceOverlayTextPosition(GSConfig.OsdPerformancePos, margin, history_size, GetWindowWidth(), position_y);
ImGui::SetNextWindowPos(window_pos);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.25f));
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_PlotLines, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
@@ -336,20 +424,59 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
text.clear();
text.append_format("Max: {:.1f} ms", max);
text_size = fixed_font->CalcTextSizeA(fixed_font->FontSize, FLT_MAX, 0.0f, text.c_str(), text.c_str() + text.length());
win_dl->AddText(ImVec2((GSConfig.OsdPerformancePos == OsdOverlayPos::TopLeft ? 2.0f * spacing : wpos.x + history_size.x - text_size.x - spacing) + shadow_offset,
wpos.y + shadow_offset),
float text_x;
switch (GSConfig.OsdPerformancePos)
{
case OsdOverlayPos::TopLeft:
case OsdOverlayPos::CenterLeft:
case OsdOverlayPos::BottomLeft:
text_x = wpos.x + 2.0f * spacing; // Left alignment within window
break;
case OsdOverlayPos::TopCenter:
case OsdOverlayPos::Center:
case OsdOverlayPos::BottomCenter:
text_x = wpos.x + (history_size.x - text_size.x) * 0.5f; // Center alignment within window
break;
case OsdOverlayPos::TopRight:
case OsdOverlayPos::CenterRight:
case OsdOverlayPos::BottomRight:
default:
text_x = wpos.x + history_size.x - text_size.x - spacing; // Right alignment within window
break;
}
win_dl->AddText(ImVec2(text_x + shadow_offset, wpos.y + shadow_offset),
IM_COL32(0, 0, 0, 100), text.c_str(), text.c_str() + text.length());
win_dl->AddText(ImVec2((GSConfig.OsdPerformancePos == OsdOverlayPos::TopLeft ? 2.0f * spacing : wpos.x + history_size.x - text_size.x - spacing), wpos.y),
win_dl->AddText(ImVec2(text_x, wpos.y),
IM_COL32(255, 255, 255, 255), text.c_str(), text.c_str() + text.length());
text.clear();
text.append_format("Min: {:.1f} ms", min);
text_size = fixed_font->CalcTextSizeA(fixed_font->FontSize, FLT_MAX, 0.0f, text.c_str(), text.c_str() + text.length());
win_dl->AddText(ImVec2((GSConfig.OsdPerformancePos == OsdOverlayPos::TopLeft ? 2.0f * spacing : wpos.x + history_size.x - text_size.x - spacing) + shadow_offset,
wpos.y + history_size.y - fixed_font->FontSize + shadow_offset),
float min_text_x;
switch (GSConfig.OsdPerformancePos)
{
case OsdOverlayPos::TopLeft:
case OsdOverlayPos::CenterLeft:
case OsdOverlayPos::BottomLeft:
min_text_x = wpos.x + 2.0f * spacing; // Left alignment within window
break;
case OsdOverlayPos::TopCenter:
case OsdOverlayPos::Center:
case OsdOverlayPos::BottomCenter:
min_text_x = wpos.x + (history_size.x - text_size.x) * 0.5f; // Center alignment within window
break;
case OsdOverlayPos::TopRight:
case OsdOverlayPos::CenterRight:
case OsdOverlayPos::BottomRight:
default:
min_text_x = wpos.x + history_size.x - text_size.x - spacing; // Right alignment within window
break;
}
win_dl->AddText(ImVec2(min_text_x + shadow_offset, wpos.y + history_size.y - fixed_font->FontSize + shadow_offset),
IM_COL32(0, 0, 0, 100), text.c_str(), text.c_str() + text.length());
win_dl->AddText(ImVec2((GSConfig.OsdPerformancePos == OsdOverlayPos::TopLeft ? 2.0f * spacing : wpos.x + history_size.x - text_size.x - spacing),
wpos.y + history_size.y - fixed_font->FontSize),
win_dl->AddText(ImVec2(min_text_x, wpos.y + history_size.y - fixed_font->FontSize),
IM_COL32(255, 255, 255, 255), text.c_str(), text.c_str() + text.length());
}
ImGui::End();
@@ -362,7 +489,12 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
{
if (GSConfig.OsdShowIndicators)
{
DRAW_LINE(standard_font, ICON_FA_PAUSE, IM_COL32(255, 255, 255, 255));
// We should put the Pause icon in the top right regardless of performance overlay position
text = ICON_FA_PAUSE;
text_size = standard_font->CalcTextSizeA(standard_font->FontSize, std::numeric_limits<float>::max(), -1.0f, text.c_str(), nullptr, nullptr);
const ImVec2 pause_pos(GetWindowWidth() - margin - text_size.x, margin);
dl->AddText(standard_font, standard_font->FontSize, ImVec2(pause_pos.x + shadow_offset, pause_pos.y + shadow_offset), IM_COL32(0, 0, 0, 100), text.c_str());
dl->AddText(standard_font, standard_font->FontSize, pause_pos, IM_COL32(255, 255, 255, 255), text.c_str());
}
}
@@ -1147,7 +1279,7 @@ void ImGuiManager::RenderOverlays()
{
const float scale = ImGuiManager::GetGlobalScale();
const float margin = std::ceil(10.0f * scale);
const float spacing = std::ceil(5.0f * scale);
const float spacing = std::ceil(5.0f * scale);
float position_y = margin;
DrawVideoCaptureOverlay(position_y, scale, margin, spacing);
+7
View File
@@ -4,12 +4,19 @@
#pragma once
#include "ImGuiManager.h"
#include "Config.h"
struct ImVec2;
namespace ImGuiManager
{
void RenderOverlays();
}
ImVec2 CalculateOSDPosition(OsdOverlayPos position, float margin, const ImVec2& text_size, float window_width, float window_height);
ImVec2 CalculatePerformanceOverlayTextPosition(OsdOverlayPos position, float margin, const ImVec2& text_size, float window_width, float position_y);
bool ShouldUseLeftAlignment(OsdOverlayPos position);
namespace SaveStateSelectorUI
{
static constexpr float DEFAULT_OPEN_TIME = 5.0f;
+16 -1
View File
@@ -671,6 +671,18 @@ const char* Pcsx2Config::GSOptions::CaptureContainers[] = {
nullptr};
const char* Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER = "mp4";
const char* Pcsx2Config::AchievementsOptions::OverlayPositionNames[(size_t)AchievementOverlayPosition::MaxCount + 1] = {
"TopLeft",
"TopCenter",
"TopRight",
"CenterLeft",
"Center",
"CenterRight",
"BottomLeft",
"BottomCenter",
"BottomRight",
nullptr};
const char* Pcsx2Config::GSOptions::GetRendererName(GSRendererType type)
{
switch (type)
@@ -1863,6 +1875,8 @@ void Pcsx2Config::AchievementsOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBool(Overlays);
SettingsWrapEntry(NotificationsDuration);
SettingsWrapEntry(LeaderboardsDuration);
SettingsWrapIntEnumEx(OverlayPosition, "OverlayPosition");
SettingsWrapIntEnumEx(NotificationPosition, "NotificationPosition");
SettingsWrapEntry(InfoSoundName);
SettingsWrapEntry(UnlockSoundName);
SettingsWrapEntry(LBSubmitSoundName);
@@ -1877,7 +1891,8 @@ void Pcsx2Config::AchievementsOptions::LoadSave(SettingsWrapper& wrap)
bool Pcsx2Config::AchievementsOptions::operator==(const AchievementsOptions& right) const
{
return OpEqu(bitset) && OpEqu(NotificationsDuration) && OpEqu(LeaderboardsDuration);
return OpEqu(bitset) && OpEqu(NotificationsDuration) && OpEqu(LeaderboardsDuration) &&
OpEqu(OverlayPosition) && OpEqu(NotificationPosition);
}
bool Pcsx2Config::AchievementsOptions::operator!=(const AchievementsOptions& right) const
+61
View File
@@ -5,6 +5,7 @@
#include "SIO/Memcard/MemoryCardFolder.h"
#include "SIO/Sio.h"
#include <SIO/SioTypes.h>
#include "common/Assertions.h"
#include "common/Console.h"
@@ -18,6 +19,7 @@
#include "Config.h"
#include "Host.h"
#include "VMManager.h"
#include "IconsPromptFont.h"
#include "fmt/format.h"
@@ -636,6 +638,65 @@ void FileMcd_Reopen(std::string new_serial)
FileMcd_EmuOpen();
}
static bool FileMcd_IsAutoEjecting()
{
for (size_t port = 0; port < SIO::PORTS; ++port)
{
for (size_t slot = 0; slot < SIO::SLOTS; ++slot)
{
if (mcds[port][slot].autoEjectTicks > 0)
{
return true; // Auto-eject is active
}
}
}
return false; // No auto-eject active
}
void FileMcd_Swap()
{
if (MemcardBusy::IsBusy())
{
Host::AddIconOSDMessage("MemoryCardSwap_Busy", ICON_PF_MEMORY_CARD, TRANSLATE_SV("MemoryCardSwap_Busy", "Memory cards are busy. Can't swap right now."));
return;
}
// Check if auto-eject is active
if (FileMcd_IsAutoEjecting())
{
Host::AddIconOSDMessage("MemoryCardSwap_AutoEject", ICON_PF_MEMORY_CARD, TRANSLATE_SV("MemoryCardSwap_AutoEject", "Memory cards are being auto-ejected. Can't swap right now."));
return;
}
const std::string card1Filename = Host::GetStringSettingValue("MemoryCards", "Slot1_Filename");
const std::string card2Filename = Host::GetStringSettingValue("MemoryCards", "Slot2_Filename");
// Copy each McdOptions to local memory
Pcsx2Config::McdOptions firstSlot = EmuConfig.Mcd[0];
Pcsx2Config::McdOptions secondSlot = EmuConfig.Mcd[1];
if (!firstSlot.Enabled || !secondSlot.Enabled || card1Filename.empty() || card2Filename.empty())
{
Host::AddIconOSDMessage("MemoryCardSwap_EmptySlot", ICON_PF_MEMORY_CARD, TRANSLATE_SV("MemoryCard_EmptySlot", "Both slots must have a card selected to swap."));
return;
}
// Swap them
Host::SetBaseStringSettingValue("MemoryCards", "Slot1_Filename", card2Filename.c_str());
Host::SetBaseStringSettingValue("MemoryCards", "Slot2_Filename", card1Filename.c_str());
Host::CommitBaseSettingChanges();
VMManager::ApplySettings();
EmuConfig.Mcd[0] = secondSlot;
EmuConfig.Mcd[1] = firstSlot;
// Reopen them
FileMcd_EmuClose();
FileMcd_SetType();
FileMcd_EmuOpen();
AutoEject::SetAll();
Host::AddIconOSDMessage("MemoryCardSwap", ICON_PF_MEMORY_CARD, fmt::format(TRANSLATE_FS("MemoryCardSwap", "Memory Cards have been swapped.\nSlot 1: {}\nSlot 2: {}"), EmuConfig.Mcd[0].Filename, EmuConfig.Mcd[1].Filename), Host::OSD_INFO_DURATION);
}
s32 FileMcd_IsPresent(uint port, uint slot)
{
const uint combinedSlot = FileMcd_ConvertToSlot(port, slot);
+1
View File
@@ -42,6 +42,7 @@ void FileMcd_EmuOpen();
void FileMcd_EmuClose();
void FileMcd_CancelEject();
void FileMcd_Reopen(std::string new_serial);
void FileMcd_Swap();
s32 FileMcd_IsPresent(uint port, uint slot);
void FileMcd_GetSizeInfo(uint port, uint slot, McdSizeInfo* outways);
bool FileMcd_IsPSX(uint port, uint slot);