mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
748f232976 | ||
|
|
a33612cf7d | ||
|
|
5c123f3183 | ||
|
|
d30a7fb991 | ||
|
|
d4f661c27c | ||
|
|
6d05d0220d | ||
|
|
7fab935c2d | ||
|
|
cd120c3cfd | ||
|
|
0180ec060b | ||
|
|
cf4412ecbe | ||
|
|
743b0b11d8 | ||
|
|
e8c2cfa843 | ||
|
|
764875ddbf | ||
|
|
92c7eaa383 | ||
|
|
4d2c1a82c9 | ||
|
|
eb50aaea35 | ||
|
|
d69c71e058 | ||
|
|
7cc8c7eee6 | ||
|
|
dd96f2c296 | ||
|
|
3cb2f3d2d9 | ||
|
|
1f9a9940e9 | ||
|
|
8164f2b2db | ||
|
|
d0c54de330 | ||
|
|
af5cd8d48e | ||
|
|
a43f051852 | ||
|
|
0f8c5066e3 | ||
|
|
1bf1f458d0 | ||
|
|
5ef1993496 | ||
|
|
80baa73578 | ||
|
|
b46c85ee7f | ||
|
|
7f233ca620 | ||
|
|
47fe2344a5 | ||
|
|
4e763d6ff7 | ||
|
|
e1cc994cca | ||
|
|
5b7f85e571 | ||
|
|
7475cfb325 | ||
|
|
cee01a22e1 | ||
|
|
c6437bccad | ||
|
|
7419311296 | ||
|
|
2807a06d76 |
2
.github/ISSUE_TEMPLATE/app_bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/app_bug_report.yaml
vendored
@ -59,7 +59,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: PCSX2 Revision
|
label: PCSX2 Revision
|
||||||
description: "Please ensure you are on the latest version before making an issue"
|
description: "Please ensure you are on the latest version before making an issue"
|
||||||
placeholder: "Example: v1.7.1337"
|
placeholder: "Example: v2.5.374"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/emu_bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/emu_bug_report.yaml
vendored
@ -76,7 +76,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: PCSX2 Revision
|
label: PCSX2 Revision
|
||||||
description: "We only accept bug reports for the latest dev version. Please try upgrading before making an issue."
|
description: "We only accept bug reports for the latest dev version. Please try upgrading before making an issue."
|
||||||
placeholder: "Example: v1.7.1337"
|
placeholder: "Example: v2.5.374"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
|||||||
@ -17,7 +17,7 @@ jobs:
|
|||||||
run: ./.github/workflows/scripts/common/update_base_translation.sh
|
run: ./.github/workflows/scripts/common/update_base_translation.sh
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676
|
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725
|
||||||
with:
|
with:
|
||||||
title: "Qt: Update Base Translation"
|
title: "Qt: Update Base Translation"
|
||||||
commit-message: "[ci skip] Qt: Update Base Translation."
|
commit-message: "[ci skip] Qt: Update Base Translation."
|
||||||
|
|||||||
@ -19,7 +19,7 @@ jobs:
|
|||||||
mv ./game_controller_db.txt ${{github.workspace}}/bin/resources/game_controller_db.txt
|
mv ./game_controller_db.txt ${{github.workspace}}/bin/resources/game_controller_db.txt
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676
|
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725
|
||||||
with:
|
with:
|
||||||
title: "PAD: Update to latest controller database"
|
title: "PAD: Update to latest controller database"
|
||||||
commit-message: "[ci skip] PAD: Update to latest controller database."
|
commit-message: "[ci skip] PAD: Update to latest controller database."
|
||||||
|
|||||||
2
.github/workflows/linux_build_flatpak.yml
vendored
2
.github/workflows/linux_build_flatpak.yml
vendored
@ -153,7 +153,7 @@ jobs:
|
|||||||
mv "./${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak" "$GITHUB_WORKSPACE"/ci-artifacts/
|
mv "./${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak" "$GITHUB_WORKSPACE"/ci-artifacts/
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||||
path: ci-artifacts
|
path: ci-artifacts
|
||||||
|
|||||||
6
.github/workflows/linux_build_qt.yml
vendored
6
.github/workflows/linux_build_qt.yml
vendored
@ -92,7 +92,7 @@ jobs:
|
|||||||
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: ccache cache files
|
- name: ccache cache files
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: .ccache
|
path: .ccache
|
||||||
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||||
@ -114,7 +114,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
id: cache-deps
|
id: cache-deps
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: ~/deps
|
path: ~/deps
|
||||||
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/linux/build-dependencies-qt.sh', '.github/workflows/scripts/common/*.patch') }}
|
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/linux/build-dependencies-qt.sh', '.github/workflows/scripts/common/*.patch') }}
|
||||||
@ -174,7 +174,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
if: inputs.buildAppImage == true
|
if: inputs.buildAppImage == true
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||||
path: ci-artifacts
|
path: ci-artifacts
|
||||||
|
|||||||
6
.github/workflows/macos_build.yml
vendored
6
.github/workflows/macos_build.yml
vendored
@ -91,7 +91,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
id: cache-deps
|
id: cache-deps
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: ~/deps
|
path: ~/deps
|
||||||
key: ${{ inputs.os }} deps ${{ hashFiles('.github/workflows/scripts/macos/*', '.github/workflows/scripts/common/*.patch') }}
|
key: ${{ inputs.os }} deps ${{ hashFiles('.github/workflows/scripts/macos/*', '.github/workflows/scripts/common/*.patch') }}
|
||||||
@ -112,7 +112,7 @@ jobs:
|
|||||||
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Cache ccache cache
|
- name: Cache ccache cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: .ccache
|
path: .ccache
|
||||||
key: ${{ inputs.os }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
key: ${{ inputs.os }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||||
@ -197,7 +197,7 @@ jobs:
|
|||||||
cp "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" ci-artifacts/macOS.tar.xz
|
cp "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" ci-artifacts/macOS.tar.xz
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||||
path: "*.tar.xz"
|
path: "*.tar.xz"
|
||||||
|
|||||||
2
.github/workflows/release_cut_new.yml
vendored
2
.github/workflows/release_cut_new.yml
vendored
@ -168,7 +168,7 @@ jobs:
|
|||||||
- name: Prepare Artifact Folder
|
- name: Prepare Artifact Folder
|
||||||
run: mkdir ./ci-artifacts/
|
run: mkdir ./ci-artifacts/
|
||||||
|
|
||||||
- uses: actions/download-artifact@v6
|
- uses: actions/download-artifact@v7
|
||||||
name: Download all Artifacts
|
name: Download all Artifacts
|
||||||
with:
|
with:
|
||||||
path: ./ci-artifacts/
|
path: ./ci-artifacts/
|
||||||
|
|||||||
@ -23,7 +23,7 @@ FREETYPE=2.14.1
|
|||||||
HARFBUZZ=12.2.0
|
HARFBUZZ=12.2.0
|
||||||
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
|
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
|
||||||
LIBJPEGTURBO=3.1.2
|
LIBJPEGTURBO=3.1.2
|
||||||
LIBPNG=1.6.51
|
LIBPNG=1.6.53
|
||||||
LIBWEBP=1.6.0
|
LIBWEBP=1.6.0
|
||||||
NVENC=11.1.5.3
|
NVENC=11.1.5.3
|
||||||
SDL=SDL3-3.2.26
|
SDL=SDL3-3.2.26
|
||||||
@ -52,10 +52,10 @@ b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG
|
|||||||
f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARFBUZZ.tar.gz
|
f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARFBUZZ.tar.gz
|
||||||
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
|
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
|
||||||
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||||
a050a892d3b4a7bb010c3a95c7301e49656d72a64f1fc709a90b8aded192bed2 libpng-$LIBPNG.tar.xz
|
1d3fb8ccc2932d04aa3663e22ef5ef490244370f4e568d7850165068778d98d4 libpng-$LIBPNG.tar.xz
|
||||||
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
|
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
|
||||||
dad488474a51a0b01d547cd2834893d6299328d2e30f479a3564088b5476bae2 $SDL.tar.gz
|
dad488474a51a0b01d547cd2834893d6299328d2e30f479a3564088b5476bae2 $SDL.tar.gz
|
||||||
9c16ec5654be709f062a705d0c6f529193f1c2123fe7f102fda6733913689023 libpng-$LIBPNG-apng.patch.gz
|
452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c libpng-$LIBPNG-apng.patch.gz
|
||||||
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
||||||
2974b91062197e0527dffa3aadd8fe3bfa6681ae45f5ff9181bc0ca6479abd59 nv-codec-headers-$NVENC.tar.gz
|
2974b91062197e0527dffa3aadd8fe3bfa6681ae45f5ff9181bc0ca6479abd59 nv-codec-headers-$NVENC.tar.gz
|
||||||
c465aa56757e7746ac707f582b6e2d51546569a4a2488c1172fb543aa5fdfc2c vulkan-sdk-$VULKAN.tar.gz
|
c465aa56757e7746ac707f582b6e2d51546569a4a2488c1172fb543aa5fdfc2c vulkan-sdk-$VULKAN.tar.gz
|
||||||
|
|||||||
@ -14,21 +14,21 @@
|
|||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://downloads.sourceforge.net/project/libpng/libpng16/1.6.51/libpng-1.6.51.tar.xz",
|
"url": "https://downloads.sourceforge.net/project/libpng/libpng16/1.6.53/libpng-1.6.53.tar.xz",
|
||||||
"sha256": "a050a892d3b4a7bb010c3a95c7301e49656d72a64f1fc709a90b8aded192bed2"
|
"sha256": "1d3fb8ccc2932d04aa3663e22ef5ef490244370f4e568d7850165068778d98d4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"url": "https://download.sourceforge.net/libpng-apng/libpng-1.6.51-apng.patch.gz",
|
"url": "https://download.sourceforge.net/libpng-apng/libpng-1.6.53-apng.patch.gz",
|
||||||
"dest-filename": "libpng-1.6.51-apng.patch.gz",
|
"dest-filename": "libpng-1.6.53-apng.patch.gz",
|
||||||
"sha256": "9c16ec5654be709f062a705d0c6f529193f1c2123fe7f102fda6733913689023"
|
"sha256": "452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"commands":
|
"commands":
|
||||||
[
|
[
|
||||||
"gunzip -f libpng-1.6.51-apng.patch.gz",
|
"gunzip -f libpng-1.6.53-apng.patch.gz",
|
||||||
"patch -p1 < \"libpng-1.6.51-apng.patch\""
|
"patch -p1 < \"libpng-1.6.53-apng.patch\""
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@ -43,7 +43,7 @@ HARFBUZZ=12.2.0
|
|||||||
SDL=SDL3-3.2.26
|
SDL=SDL3-3.2.26
|
||||||
ZSTD=1.5.7
|
ZSTD=1.5.7
|
||||||
LZ4=1.10.0
|
LZ4=1.10.0
|
||||||
LIBPNG=1.6.51
|
LIBPNG=1.6.53
|
||||||
LIBJPEGTURBO=3.1.2
|
LIBJPEGTURBO=3.1.2
|
||||||
LIBWEBP=1.6.0
|
LIBWEBP=1.6.0
|
||||||
FFMPEG=8.0
|
FFMPEG=8.0
|
||||||
@ -83,9 +83,9 @@ f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARF
|
|||||||
dad488474a51a0b01d547cd2834893d6299328d2e30f479a3564088b5476bae2 $SDL.tar.gz
|
dad488474a51a0b01d547cd2834893d6299328d2e30f479a3564088b5476bae2 $SDL.tar.gz
|
||||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||||
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
||||||
a050a892d3b4a7bb010c3a95c7301e49656d72a64f1fc709a90b8aded192bed2 libpng-$LIBPNG.tar.xz
|
1d3fb8ccc2932d04aa3663e22ef5ef490244370f4e568d7850165068778d98d4 libpng-$LIBPNG.tar.xz
|
||||||
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
|
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
|
||||||
9c16ec5654be709f062a705d0c6f529193f1c2123fe7f102fda6733913689023 libpng-$LIBPNG-apng.patch.gz
|
452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c libpng-$LIBPNG-apng.patch.gz
|
||||||
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||||
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
|
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
|
||||||
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
|
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
|
||||||
|
|||||||
@ -25,7 +25,7 @@ HARFBUZZ=12.2.0
|
|||||||
SDL=SDL3-3.2.26
|
SDL=SDL3-3.2.26
|
||||||
ZSTD=1.5.7
|
ZSTD=1.5.7
|
||||||
LZ4=1.10.0
|
LZ4=1.10.0
|
||||||
LIBPNG=1.6.51
|
LIBPNG=1.6.53
|
||||||
LIBJPEGTURBO=3.1.2
|
LIBJPEGTURBO=3.1.2
|
||||||
LIBWEBP=1.6.0
|
LIBWEBP=1.6.0
|
||||||
FFMPEG=8.0
|
FFMPEG=8.0
|
||||||
@ -64,9 +64,9 @@ f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARF
|
|||||||
dad488474a51a0b01d547cd2834893d6299328d2e30f479a3564088b5476bae2 $SDL.tar.gz
|
dad488474a51a0b01d547cd2834893d6299328d2e30f479a3564088b5476bae2 $SDL.tar.gz
|
||||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||||
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
||||||
a050a892d3b4a7bb010c3a95c7301e49656d72a64f1fc709a90b8aded192bed2 libpng-$LIBPNG.tar.xz
|
1d3fb8ccc2932d04aa3663e22ef5ef490244370f4e568d7850165068778d98d4 libpng-$LIBPNG.tar.xz
|
||||||
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
|
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
|
||||||
9c16ec5654be709f062a705d0c6f529193f1c2123fe7f102fda6733913689023 libpng-$LIBPNG-apng.patch.gz
|
452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c libpng-$LIBPNG-apng.patch.gz
|
||||||
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||||
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
|
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
|
||||||
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
|
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
|
||||||
|
|||||||
@ -45,8 +45,8 @@ cd "%BUILDDIR%"
|
|||||||
set FREETYPE=2.14.1
|
set FREETYPE=2.14.1
|
||||||
set HARFBUZZ=12.2.0
|
set HARFBUZZ=12.2.0
|
||||||
set LIBJPEGTURBO=3.1.2
|
set LIBJPEGTURBO=3.1.2
|
||||||
set LIBPNG=1651
|
set LIBPNG=1653
|
||||||
set LIBPNGLONG=1.6.51
|
set LIBPNGLONG=1.6.53
|
||||||
set SDL=SDL3-3.2.26
|
set SDL=SDL3-3.2.26
|
||||||
set QT=6.10.1
|
set QT=6.10.1
|
||||||
set QTMINOR=6.10
|
set QTMINOR=6.10
|
||||||
@ -67,8 +67,8 @@ set SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
|
|||||||
|
|
||||||
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 174d9e53402e1bf9ec7277e22ec199ba3e55a6be2c0740cb18c0ee9850fc8c34 || goto error
|
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 174d9e53402e1bf9ec7277e22ec199ba3e55a6be2c0740cb18c0ee9850fc8c34 || goto error
|
||||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 31490c781bacd2ce56862555b11c51c964977c39f14f51b817dfaecf0be089fe || goto error
|
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 31490c781bacd2ce56862555b11c51c964977c39f14f51b817dfaecf0be089fe || goto error
|
||||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1651.zip 31c2c6505fc1bb613574fd12357684b4e0292650607416ef1e68e6e4e0c470c8 || goto error
|
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1653.zip 140566abc64bb2320cb35f1d154d1cb3eb7174a12234d33bfdffb446bdc0a1d2 || goto error
|
||||||
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz 9c16ec5654be709f062a705d0c6f529193f1c2123fe7f102fda6733913689023 || goto error
|
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz 452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c || goto error
|
||||||
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf || goto error
|
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf || goto error
|
||||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
|
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
|
||||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 739356eef1192fff9d641c320a8f5ef4a10506b8927def4b9ceb764c7e947369 || goto error
|
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 739356eef1192fff9d641c320a8f5ef4a10506b8927def4b9ceb764c7e947369 || goto error
|
||||||
|
|||||||
@ -43,8 +43,8 @@ cd "%BUILDDIR%"
|
|||||||
set FREETYPE=2.14.1
|
set FREETYPE=2.14.1
|
||||||
set HARFBUZZ=12.2.0
|
set HARFBUZZ=12.2.0
|
||||||
set LIBJPEGTURBO=3.1.2
|
set LIBJPEGTURBO=3.1.2
|
||||||
set LIBPNG=1651
|
set LIBPNG=1653
|
||||||
set LIBPNGLONG=1.6.51
|
set LIBPNGLONG=1.6.53
|
||||||
set SDL=SDL3-3.2.26
|
set SDL=SDL3-3.2.26
|
||||||
set QT=6.10.1
|
set QT=6.10.1
|
||||||
set QTMINOR=6.10
|
set QTMINOR=6.10
|
||||||
@ -65,8 +65,8 @@ set SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
|
|||||||
|
|
||||||
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 174d9e53402e1bf9ec7277e22ec199ba3e55a6be2c0740cb18c0ee9850fc8c34 || goto error
|
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 174d9e53402e1bf9ec7277e22ec199ba3e55a6be2c0740cb18c0ee9850fc8c34 || goto error
|
||||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 31490c781bacd2ce56862555b11c51c964977c39f14f51b817dfaecf0be089fe || goto error
|
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 31490c781bacd2ce56862555b11c51c964977c39f14f51b817dfaecf0be089fe || goto error
|
||||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1651.zip 31c2c6505fc1bb613574fd12357684b4e0292650607416ef1e68e6e4e0c470c8 || goto error
|
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1653.zip 140566abc64bb2320cb35f1d154d1cb3eb7174a12234d33bfdffb446bdc0a1d2 || goto error
|
||||||
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz 9c16ec5654be709f062a705d0c6f529193f1c2123fe7f102fda6733913689023 || goto error
|
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz 452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c || goto error
|
||||||
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf || goto error
|
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf || goto error
|
||||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
|
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
|
||||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 739356eef1192fff9d641c320a8f5ef4a10506b8927def4b9ceb764c7e947369 || goto error
|
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 739356eef1192fff9d641c320a8f5ef4a10506b8927def4b9ceb764c7e947369 || goto error
|
||||||
|
|||||||
6
.github/workflows/windows_build_qt.yml
vendored
6
.github/workflows/windows_build_qt.yml
vendored
@ -115,7 +115,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
id: cache-deps
|
id: cache-deps
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: deps
|
path: deps
|
||||||
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/windows/build-dependencies.bat', '.github/workflows/scripts/common/*.patch') }}
|
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/windows/build-dependencies.bat', '.github/workflows/scripts/common/*.patch') }}
|
||||||
@ -154,7 +154,7 @@ jobs:
|
|||||||
cmake --build build --config Release --target unittests
|
cmake --build build --config Release --target unittests
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||||
path: |
|
path: |
|
||||||
@ -186,7 +186,7 @@ jobs:
|
|||||||
}
|
}
|
||||||
|
|
||||||
- name: Upload artifact - with symbols
|
- name: Upload artifact - with symbols
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}-symbols
|
name: ${{ steps.artifact-metadata.outputs.artifact-name }}-symbols
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@ -78,7 +78,7 @@
|
|||||||
03000000c82d00001230000000000000,8BitDo Ultimate,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,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
03000000c82d00001230000000000000,8BitDo Ultimate,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,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||||
03000000c82d00001260000000000000,8BitDo Ultimate 2,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,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
03000000c82d00001260000000000000,8BitDo Ultimate 2,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,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||||
03000000c82d00001b30000000000000,8BitDo Ultimate 2C,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,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
03000000c82d00001b30000000000000,8BitDo Ultimate 2C,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,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||||
03000000c82d00001c30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,paddle1:b2,paddle2:b5,platform:Windows,
|
03000000c82d00001c30000000000000,8BitDo Ultimate 2C,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,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||||
03000000c82d00001d30000000000000,8BitDo Ultimate 2C,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,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
03000000c82d00001d30000000000000,8BitDo Ultimate 2C,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,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||||
03000000c82d00001530000000000000,8BitDo Ultimate C,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,
|
03000000c82d00001530000000000000,8BitDo Ultimate C,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,
|
||||||
03000000c82d00001630000000000000,8BitDo Ultimate C,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,
|
03000000c82d00001630000000000000,8BitDo Ultimate C,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,
|
||||||
@ -985,6 +985,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
|||||||
030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X,
|
030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||||
03000000242f00002d00000007010000,JYS Adapter,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:Mac OS X,
|
03000000242f00002d00000007010000,JYS Adapter,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:Mac OS X,
|
||||||
030000006d04000019c2000000000000,Logitech 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:Mac OS X,
|
030000006d04000019c2000000000000,Logitech 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:Mac OS X,
|
||||||
|
030000006d04000019c2000000020000,Logitech Cordless RumblePad 2,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:Mac OS X,
|
||||||
030000006d04000016c2000000020000,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:Mac OS X,
|
030000006d04000016c2000000020000,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:Mac OS X,
|
||||||
030000006d04000016c2000000030000,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:Mac OS X,
|
030000006d04000016c2000000030000,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:Mac OS X,
|
||||||
030000006d04000016c2000014040000,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:Mac OS X,
|
030000006d04000016c2000014040000,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:Mac OS X,
|
||||||
@ -993,7 +994,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
|||||||
030000006d04000019c2000005030000,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:Mac OS X,
|
030000006d04000019c2000005030000,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:Mac OS X,
|
||||||
030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||||
030000006d04000018c2000000010000,Logitech RumblePad 2,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:Mac OS X,
|
030000006d04000018c2000000010000,Logitech RumblePad 2,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:Mac OS X,
|
||||||
030000006d04000019c2000000020000,Logitech Cordless RumblePad 2,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:Mac OS X,
|
|
||||||
03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,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,
|
03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,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,
|
||||||
03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,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,
|
03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,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,
|
||||||
03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,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,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
|
03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,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,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
|
||||||
@ -1395,6 +1395,10 @@ 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,
|
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,
|
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,
|
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,
|
||||||
|
03000000d80400004bea000011010000,icedragon.io STAC Dance Pad,a:b0,b:b1,x:b2,y:b3,back:b4,platform:Linux,
|
||||||
|
03000000d80400004aea000011010000,icedragon.io STAC Dance Pad,a:b0,b:b1,x:b2,y:b3,back:b4,platform:Linux,
|
||||||
|
030000008a2e0000d910000011010000,icedragon.io STAC2 Dance Pad,a:b0,b:b1,x:b2,y:b3,back:b4,platform:Linux,
|
||||||
|
030000008a2e0000e910000011010000,icedragon.io STAC2 Dance Pad,a:b8,b:b9,x:b10,y:b11,back:b12,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,
|
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,
|
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,
|
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,
|
||||||
@ -1591,6 +1595,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
|||||||
030000006d040000d2ca000011010000,Precision 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,
|
030000006d040000d2ca000011010000,Precision 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,
|
||||||
03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux,
|
03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux,
|
||||||
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||||
|
03000000120c0000160e000011010000,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:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||||
03000000341a00003608000011010000,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:Linux,
|
03000000341a00003608000011010000,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:Linux,
|
||||||
030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
|
030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
|
||||||
030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
|
030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
|
||||||
@ -1701,7 +1706,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
|||||||
03000000952e00004e43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,
|
03000000952e00004e43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,
|
||||||
03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux,
|
03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux,
|
||||||
03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,
|
03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,
|
||||||
03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
|
|
||||||
03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
|
03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
|
||||||
03000000632500002305000010010000,ShanWan 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,
|
03000000632500002305000010010000,ShanWan 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,
|
||||||
03000000632500002605000010010000,ShanWan Gamepad,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,
|
03000000632500002605000010010000,ShanWan Gamepad,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,
|
||||||
@ -1858,4 +1862,5 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
|||||||
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,
|
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,
|
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,
|
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,
|
||||||
|
03000000790000002201000011010000,ZhiXu GuliKit D,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,
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include "RedtapeWindows.h"
|
#include "common/RedtapeWindows.h"
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <pathcch.h>
|
#include <pathcch.h>
|
||||||
|
|||||||
@ -1148,7 +1148,7 @@ bool BMPBufferLoader(RGBA8Image* image, const void* buffer, size_t buffer_size)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (width > 65536 || height > 65536)
|
if (width >= 65536 || height >= 65536)
|
||||||
{
|
{
|
||||||
Console.Error("BMP dimensions too large: %ux%u", width, height);
|
Console.Error("BMP dimensions too large: %ux%u", width, height);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -272,7 +272,7 @@ if (NOT APPLE)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(GLOB TS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Translations/*.ts)
|
file(GLOB TS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Translations/pcsx2-qt_*-*.ts)
|
||||||
|
|
||||||
target_precompile_headers(pcsx2-qt PRIVATE PrecompiledHeader.h)
|
target_precompile_headers(pcsx2-qt PRIVATE PrecompiledHeader.h)
|
||||||
set_source_files_properties(PrecompiledHeader.cpp PROPERTIES HEADER_FILE_ONLY TRUE)
|
set_source_files_properties(PrecompiledHeader.cpp PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||||
|
|||||||
@ -220,6 +220,8 @@ void GameListWidget::initialize()
|
|||||||
m_sort_model->setSourceModel(m_model);
|
m_sort_model->setSourceModel(m_model);
|
||||||
|
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
m_ui.stack->installEventFilter(this);
|
||||||
|
m_ui.stack->setAutoFillBackground(false);
|
||||||
|
|
||||||
for (u32 type = 0; type < static_cast<u32>(GameList::EntryType::Count); type++)
|
for (u32 type = 0; type < static_cast<u32>(GameList::EntryType::Count); type++)
|
||||||
{
|
{
|
||||||
@ -353,6 +355,7 @@ void GameListWidget::setCustomBackground()
|
|||||||
m_background_movie = nullptr;
|
m_background_movie = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the path to the custom background
|
||||||
std::string path = Host::GetBaseStringSettingValue("UI", "GameListBackgroundPath");
|
std::string path = Host::GetBaseStringSettingValue("UI", "GameListBackgroundPath");
|
||||||
if (!Path::IsAbsolute(path))
|
if (!Path::IsAbsolute(path))
|
||||||
path = Path::Combine(EmuFolders::DataRoot, path);
|
path = Path::Combine(EmuFolders::DataRoot, path);
|
||||||
@ -360,27 +363,26 @@ void GameListWidget::setCustomBackground()
|
|||||||
// Only try to create background if path are valid
|
// Only try to create background if path are valid
|
||||||
if (!path.empty() && FileSystem::FileExists(path.c_str()))
|
if (!path.empty() && FileSystem::FileExists(path.c_str()))
|
||||||
{
|
{
|
||||||
QMovie* new_movie;
|
|
||||||
QString img_path = QString::fromStdString(path);
|
QString img_path = QString::fromStdString(path);
|
||||||
if (img_path.endsWith(".png", Qt::CaseInsensitive))
|
const QByteArray format = (img_path.endsWith(".png", Qt::CaseInsensitive)) ? QByteArray("apng") : QByteArray();
|
||||||
// Use apng plugin
|
m_background_movie = new QMovie(img_path, format, this);
|
||||||
new_movie = new QMovie(img_path, "apng", this);
|
if (!m_background_movie->isValid())
|
||||||
else
|
|
||||||
new_movie = new QMovie(img_path, QByteArray(), this);
|
|
||||||
|
|
||||||
if (new_movie->isValid())
|
|
||||||
m_background_movie = new_movie;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
Console.Warning("Failed to load background movie from: %s", path.c_str());
|
Console.Warning("Failed to load background movie from: %s", path.c_str());
|
||||||
delete new_movie;
|
delete m_background_movie;
|
||||||
|
m_background_movie = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is no valid background then reset fallback to default UI state
|
// If there is no valid background then reset fallback to default UI state
|
||||||
if (!m_background_movie)
|
if (!m_background_movie)
|
||||||
{
|
{
|
||||||
m_ui.stack->setPalette(QApplication::palette());
|
m_background_pixmap = QPixmap();
|
||||||
|
m_ui.stack->setAutoFillBackground(true);
|
||||||
|
m_table_view->viewport()->setAutoFillBackground(true);
|
||||||
|
m_list_view->viewport()->setAutoFillBackground(true);
|
||||||
|
|
||||||
|
m_ui.stack->update();
|
||||||
m_table_view->setAlternatingRowColors(true);
|
m_table_view->setAlternatingRowColors(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -390,7 +392,7 @@ void GameListWidget::setCustomBackground()
|
|||||||
const std::string ar_value = Host::GetBaseStringSettingValue("UI", "GameListBackgroundMode", InterfaceSettingsWidget::BACKGROUND_SCALE_NAMES[static_cast<u8>(QtUtils::ScalingMode::Fit)]);
|
const std::string ar_value = Host::GetBaseStringSettingValue("UI", "GameListBackgroundMode", InterfaceSettingsWidget::BACKGROUND_SCALE_NAMES[static_cast<u8>(QtUtils::ScalingMode::Fit)]);
|
||||||
for (u8 i = 0; i < static_cast<u8>(QtUtils::ScalingMode::MaxCount); i++)
|
for (u8 i = 0; i < static_cast<u8>(QtUtils::ScalingMode::MaxCount); i++)
|
||||||
{
|
{
|
||||||
if (!(InterfaceSettingsWidget::BACKGROUND_SCALE_NAMES[i] == nullptr))
|
if (InterfaceSettingsWidget::BACKGROUND_SCALE_NAMES[i] != nullptr)
|
||||||
{
|
{
|
||||||
if (ar_value == InterfaceSettingsWidget::BACKGROUND_SCALE_NAMES[i])
|
if (ar_value == InterfaceSettingsWidget::BACKGROUND_SCALE_NAMES[i])
|
||||||
{
|
{
|
||||||
@ -405,8 +407,13 @@ void GameListWidget::setCustomBackground()
|
|||||||
|
|
||||||
// Selected Custom background is valid, connect the signals and start animation in gamelist
|
// Selected Custom background is valid, connect the signals and start animation in gamelist
|
||||||
connect(m_background_movie, &QMovie::frameChanged, this, &GameListWidget::processBackgroundFrames, Qt::UniqueConnection);
|
connect(m_background_movie, &QMovie::frameChanged, this, &GameListWidget::processBackgroundFrames, Qt::UniqueConnection);
|
||||||
|
m_ui.stack->setAutoFillBackground(false);
|
||||||
|
|
||||||
|
m_table_view->viewport()->setAutoFillBackground(false);
|
||||||
|
m_list_view->viewport()->setAutoFillBackground(false);
|
||||||
updateCustomBackgroundState(true);
|
updateCustomBackgroundState(true);
|
||||||
m_table_view->setAlternatingRowColors(false);
|
m_table_view->setAlternatingRowColors(false);
|
||||||
|
processBackgroundFrames();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListWidget::updateCustomBackgroundState(const bool force_start)
|
void GameListWidget::updateCustomBackgroundState(const bool force_start)
|
||||||
@ -422,7 +429,7 @@ void GameListWidget::updateCustomBackgroundState(const bool force_start)
|
|||||||
|
|
||||||
void GameListWidget::processBackgroundFrames()
|
void GameListWidget::processBackgroundFrames()
|
||||||
{
|
{
|
||||||
if (m_background_movie && m_background_movie->isValid())
|
if (m_background_movie && m_background_movie->isValid() && isVisible())
|
||||||
{
|
{
|
||||||
const int widget_width = m_ui.stack->width();
|
const int widget_width = m_ui.stack->width();
|
||||||
const int widget_height = m_ui.stack->height();
|
const int widget_height = m_ui.stack->height();
|
||||||
@ -435,9 +442,8 @@ void GameListWidget::processBackgroundFrames()
|
|||||||
|
|
||||||
QtUtils::resizeAndScalePixmap(&pm, widget_width, widget_height, dpr, m_background_scaling, m_background_opacity);
|
QtUtils::resizeAndScalePixmap(&pm, widget_width, widget_height, dpr, m_background_scaling, m_background_opacity);
|
||||||
|
|
||||||
QPalette bg_palette(m_ui.stack->palette());
|
m_background_pixmap = std::move(pm);
|
||||||
bg_palette.setBrush(QPalette::Base, pm);
|
m_ui.stack->update();
|
||||||
m_ui.stack->setPalette(bg_palette);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,6 +731,7 @@ bool GameListWidget::event(QEvent* event)
|
|||||||
if (event->type() == QEvent::DevicePixelRatioChange)
|
if (event->type() == QEvent::DevicePixelRatioChange)
|
||||||
{
|
{
|
||||||
m_model->setDevicePixelRatio(devicePixelRatioF());
|
m_model->setDevicePixelRatio(devicePixelRatioF());
|
||||||
|
processBackgroundFrames();
|
||||||
QWidget::event(event);
|
QWidget::event(event);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -732,6 +739,25 @@ bool GameListWidget::event(QEvent* event)
|
|||||||
return QWidget::event(event);
|
return QWidget::event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GameListWidget::eventFilter(QObject* watched, QEvent* event)
|
||||||
|
{
|
||||||
|
if (watched == m_ui.stack && event->type() == QEvent::Paint)
|
||||||
|
{
|
||||||
|
if (!m_background_pixmap.isNull())
|
||||||
|
{
|
||||||
|
QPainter painter(m_ui.stack);
|
||||||
|
const auto* paint_event = static_cast<QPaintEvent*>(event);
|
||||||
|
painter.save();
|
||||||
|
painter.setClipRect(paint_event->rect());
|
||||||
|
painter.drawTiledPixmap(m_ui.stack->rect(), m_background_pixmap);
|
||||||
|
painter.restore();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QWidget::eventFilter(watched, event);
|
||||||
|
}
|
||||||
|
|
||||||
void GameListWidget::resizeTableViewColumnsToFit()
|
void GameListWidget::resizeTableViewColumnsToFit()
|
||||||
{
|
{
|
||||||
QtUtils::ResizeColumnsForTableView(m_table_view, {
|
QtUtils::ResizeColumnsForTableView(m_table_view, {
|
||||||
|
|||||||
@ -10,7 +10,9 @@
|
|||||||
#include "pcsx2/GameList.h"
|
#include "pcsx2/GameList.h"
|
||||||
|
|
||||||
#include <QtGui/QMovie>
|
#include <QtGui/QMovie>
|
||||||
|
#include <QtGui/QPixmap>
|
||||||
#include <QtWidgets/QListView>
|
#include <QtWidgets/QListView>
|
||||||
|
#include <QtWidgets/QStackedWidget>
|
||||||
#include <QtWidgets/QTableView>
|
#include <QtWidgets/QTableView>
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(const GameList::Entry*);
|
Q_DECLARE_METATYPE(const GameList::Entry*);
|
||||||
@ -101,6 +103,7 @@ protected:
|
|||||||
void hideEvent(QHideEvent* event) override;
|
void hideEvent(QHideEvent* event) override;
|
||||||
void resizeEvent(QResizeEvent* event) override;
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
bool event(QEvent* event) override;
|
bool event(QEvent* event) override;
|
||||||
|
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadTableHeaderState();
|
void loadTableHeaderState();
|
||||||
@ -123,6 +126,7 @@ private:
|
|||||||
GameListRefreshThread* m_refresh_thread = nullptr;
|
GameListRefreshThread* m_refresh_thread = nullptr;
|
||||||
|
|
||||||
QMovie* m_background_movie = nullptr;
|
QMovie* m_background_movie = nullptr;
|
||||||
|
QPixmap m_background_pixmap;
|
||||||
QtUtils::ScalingMode m_background_scaling = QtUtils::ScalingMode::Fit;
|
QtUtils::ScalingMode m_background_scaling = QtUtils::ScalingMode::Fit;
|
||||||
float m_background_opacity = 100.0f;
|
float m_background_opacity = 100.0f;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -37,6 +37,7 @@
|
|||||||
#include "pcsx2/PerformanceMetrics.h"
|
#include "pcsx2/PerformanceMetrics.h"
|
||||||
#include "pcsx2/Recording/InputRecording.h"
|
#include "pcsx2/Recording/InputRecording.h"
|
||||||
#include "pcsx2/Recording/InputRecordingControls.h"
|
#include "pcsx2/Recording/InputRecordingControls.h"
|
||||||
|
#include "pcsx2/SaveState.h"
|
||||||
#include "pcsx2/SIO/Sio.h"
|
#include "pcsx2/SIO/Sio.h"
|
||||||
#include "pcsx2/GS/GSExtra.h"
|
#include "pcsx2/GS/GSExtra.h"
|
||||||
|
|
||||||
@ -1192,6 +1193,12 @@ void MainWindow::cancelGameListRefresh()
|
|||||||
m_game_list_widget->cancelRefresh();
|
m_game_list_widget->cancelRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateGameListBackground()
|
||||||
|
{
|
||||||
|
if (m_game_list_widget)
|
||||||
|
m_game_list_widget->setCustomBackground();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::reportInfo(const QString& title, const QString& message)
|
void MainWindow::reportInfo(const QString& title, const QString& message)
|
||||||
{
|
{
|
||||||
QMessageBox::information(this, title, message);
|
QMessageBox::information(this, title, message);
|
||||||
@ -1213,6 +1220,103 @@ void MainWindow::onStatusMessage(const QString& message)
|
|||||||
m_ui.statusBar->showMessage(message);
|
m_ui.statusBar->showMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::reportStateLoadError(const QString& message, std::optional<s32> slot, bool backup)
|
||||||
|
{
|
||||||
|
const bool prompt_on_error = Host::GetBaseBoolSettingValue("UI", "PromptOnStateLoadSaveFailure", true);
|
||||||
|
if (!prompt_on_error)
|
||||||
|
{
|
||||||
|
SaveState_ReportLoadErrorOSD(message.toStdString(), slot, backup);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString title;
|
||||||
|
if (slot.has_value())
|
||||||
|
{
|
||||||
|
if (backup)
|
||||||
|
title = tr("Failed to Load State From Backup Slot %1").arg(*slot);
|
||||||
|
else
|
||||||
|
title = tr("Failed to Load State From Slot %1").arg(*slot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
title = tr("Failed to Load State");
|
||||||
|
}
|
||||||
|
|
||||||
|
VMLock lock(pauseAndLockVM());
|
||||||
|
|
||||||
|
QCheckBox* do_not_show_again = new QCheckBox(tr("Do not show again"));
|
||||||
|
|
||||||
|
QPointer<QMessageBox> message_box = new QMessageBox(this);
|
||||||
|
message_box->setWindowTitle(title);
|
||||||
|
message_box->setText(message);
|
||||||
|
message_box->setIcon(QMessageBox::Critical);
|
||||||
|
message_box->addButton(QMessageBox::Ok);
|
||||||
|
message_box->setDefaultButton(QMessageBox::Ok);
|
||||||
|
message_box->setCheckBox(do_not_show_again);
|
||||||
|
|
||||||
|
message_box->exec();
|
||||||
|
if (message_box.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (do_not_show_again->isChecked())
|
||||||
|
{
|
||||||
|
Host::SetBaseBoolSettingValue("UI", "PromptOnStateLoadSaveFailure", false);
|
||||||
|
Host::CommitBaseSettingChanges();
|
||||||
|
if (m_settings_window)
|
||||||
|
{
|
||||||
|
InterfaceSettingsWidget* interface_settings = m_settings_window->getInterfaceSettingsWidget();
|
||||||
|
interface_settings->updatePromptOnStateLoadSaveFailureCheckbox(Qt::Unchecked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete message_box;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::reportStateSaveError(const QString& message, std::optional<s32> slot)
|
||||||
|
{
|
||||||
|
const bool prompt_on_error = Host::GetBaseBoolSettingValue("UI", "PromptOnStateLoadSaveFailure", true);
|
||||||
|
if (!prompt_on_error)
|
||||||
|
{
|
||||||
|
SaveState_ReportSaveErrorOSD(message.toStdString(), slot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString title;
|
||||||
|
if (slot.has_value())
|
||||||
|
title = tr("Failed to Save State To Slot %1").arg(*slot);
|
||||||
|
else
|
||||||
|
title = tr("Failed to Save State");
|
||||||
|
|
||||||
|
VMLock lock(pauseAndLockVM());
|
||||||
|
|
||||||
|
QCheckBox* do_not_show_again = new QCheckBox(tr("Do not show again"));
|
||||||
|
|
||||||
|
QPointer<QMessageBox> message_box = new QMessageBox(this);
|
||||||
|
message_box->setWindowTitle(title);
|
||||||
|
message_box->setText(message);
|
||||||
|
message_box->setIcon(QMessageBox::Critical);
|
||||||
|
message_box->addButton(QMessageBox::Ok);
|
||||||
|
message_box->setDefaultButton(QMessageBox::Ok);
|
||||||
|
message_box->setCheckBox(do_not_show_again);
|
||||||
|
|
||||||
|
message_box->exec();
|
||||||
|
if (message_box.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (do_not_show_again->isChecked())
|
||||||
|
{
|
||||||
|
Host::SetBaseBoolSettingValue("UI", "PromptOnStateLoadSaveFailure", false);
|
||||||
|
Host::CommitBaseSettingChanges();
|
||||||
|
if (m_settings_window)
|
||||||
|
{
|
||||||
|
InterfaceSettingsWidget* interface_settings = m_settings_window->getInterfaceSettingsWidget();
|
||||||
|
interface_settings->updatePromptOnStateLoadSaveFailureCheckbox(Qt::Unchecked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete message_box;
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::runOnUIThread(const std::function<void()>& func)
|
void MainWindow::runOnUIThread(const std::function<void()>& func)
|
||||||
{
|
{
|
||||||
func();
|
func();
|
||||||
@ -1734,8 +1838,8 @@ void MainWindow::onCreateGameShortcutTriggered()
|
|||||||
|
|
||||||
const QString title = QString::fromStdString(entry->GetTitle());
|
const QString title = QString::fromStdString(entry->GetTitle());
|
||||||
const QString path = QString::fromStdString(entry->path);
|
const QString path = QString::fromStdString(entry->path);
|
||||||
VMLock lock(pauseAndLockVM());
|
|
||||||
ShortcutCreationDialog dlg(lock.getDialogParent(), title, path);
|
ShortcutCreationDialog dlg(this, title, path);
|
||||||
dlg.exec();
|
dlg.exec();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1876,7 +1980,7 @@ void MainWindow::onInputRecPlayActionTriggered()
|
|||||||
|
|
||||||
QFileDialog dialog(this);
|
QFileDialog dialog(this);
|
||||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||||
dialog.setWindowTitle("Select a File");
|
dialog.setWindowTitle(tr("Select a File"));
|
||||||
dialog.setNameFilter(tr("Input Recording Files (*.p2m2)"));
|
dialog.setNameFilter(tr("Input Recording Files (*.p2m2)"));
|
||||||
QStringList fileNames;
|
QStringList fileNames;
|
||||||
if (dialog.exec())
|
if (dialog.exec())
|
||||||
@ -3058,7 +3162,7 @@ void MainWindow::populateLoadStateMenu(QMenu* menu, const QString& filename, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
const u32 deleted = VMManager::DeleteSaveStates(serial.toUtf8().constData(), crc, true);
|
const u32 deleted = VMManager::DeleteSaveStates(serial.toUtf8().constData(), crc, true);
|
||||||
QMessageBox::information(this, tr("Delete Save States"), tr("%1 save states deleted.").arg(deleted));
|
QMessageBox::information(this, tr("Delete Save States"), tr("%n save states deleted.", "", deleted));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -116,10 +116,13 @@ public Q_SLOTS:
|
|||||||
void checkForUpdates(bool display_message, bool force_check);
|
void checkForUpdates(bool display_message, bool force_check);
|
||||||
void refreshGameList(bool invalidate_cache, bool popup_on_error);
|
void refreshGameList(bool invalidate_cache, bool popup_on_error);
|
||||||
void cancelGameListRefresh();
|
void cancelGameListRefresh();
|
||||||
|
void updateGameListBackground();
|
||||||
void reportInfo(const QString& title, const QString& message);
|
void reportInfo(const QString& title, const QString& message);
|
||||||
void reportError(const QString& title, const QString& message);
|
void reportError(const QString& title, const QString& message);
|
||||||
bool confirmMessage(const QString& title, const QString& message);
|
bool confirmMessage(const QString& title, const QString& message);
|
||||||
void onStatusMessage(const QString& message);
|
void onStatusMessage(const QString& message);
|
||||||
|
void reportStateLoadError(const QString& message, std::optional<s32> slot, bool backup);
|
||||||
|
void reportStateSaveError(const QString& message, std::optional<s32> slot);
|
||||||
|
|
||||||
void runOnUIThread(const std::function<void()>& func);
|
void runOnUIThread(const std::function<void()>& func);
|
||||||
void requestReset();
|
void requestReset();
|
||||||
|
|||||||
@ -1047,7 +1047,7 @@
|
|||||||
<iconset theme="camera-video"/>
|
<iconset theme="camera-video"/>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Video Capture</string>
|
<string comment="In Toolbar">&Video Capture</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEditCheats">
|
<action name="actionEditCheats">
|
||||||
|
|||||||
@ -194,6 +194,9 @@ void EmuThread::stopFullscreenUI()
|
|||||||
{
|
{
|
||||||
m_run_fullscreen_ui.store(false, std::memory_order_release);
|
m_run_fullscreen_ui.store(false, std::memory_order_release);
|
||||||
emit onFullscreenUIStateChange(false);
|
emit onFullscreenUIStateChange(false);
|
||||||
|
|
||||||
|
// Resume and refresh background when FullscreenUI exits
|
||||||
|
QMetaObject::invokeMethod(g_main_window, "updateGameListBackground", Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +302,11 @@ void EmuThread::loadState(const QString& filename)
|
|||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
if (!VMManager::LoadState(filename.toUtf8().constData(), &error))
|
if (!VMManager::LoadState(filename.toUtf8().constData(), &error))
|
||||||
Host::ReportErrorAsync(TRANSLATE_SV("QtHost", "Failed to Load State"), error.GetDescription());
|
{
|
||||||
|
QtHost::RunOnUIThread([message = QString::fromStdString(error.GetDescription())]() {
|
||||||
|
g_main_window->reportStateLoadError(message, std::nullopt, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::loadStateFromSlot(qint32 slot, bool load_backup)
|
void EmuThread::loadStateFromSlot(qint32 slot, bool load_backup)
|
||||||
@ -315,7 +322,11 @@ void EmuThread::loadStateFromSlot(qint32 slot, bool load_backup)
|
|||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
if (!VMManager::LoadStateFromSlot(slot, load_backup, &error))
|
if (!VMManager::LoadStateFromSlot(slot, load_backup, &error))
|
||||||
Host::ReportErrorAsync(TRANSLATE_SV("QtHost", "Failed to Load State"), error.GetDescription());
|
{
|
||||||
|
QtHost::RunOnUIThread([message = QString::fromStdString(error.GetDescription()), slot, load_backup]() {
|
||||||
|
g_main_window->reportStateLoadError(message, slot, load_backup);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::saveState(const QString& filename)
|
void EmuThread::saveState(const QString& filename)
|
||||||
@ -329,11 +340,11 @@ void EmuThread::saveState(const QString& filename)
|
|||||||
if (!VMManager::HasValidVM())
|
if (!VMManager::HasValidVM())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!VMManager::SaveState(filename.toUtf8().constData()))
|
VMManager::SaveState(filename.toUtf8().constData(), true, false, [](const std::string& error) {
|
||||||
{
|
QtHost::RunOnUIThread([message = QString::fromStdString(error)]() {
|
||||||
// this one is usually the result of a user-chosen path, so we can display a message box safely here
|
g_main_window->reportStateSaveError(message, std::nullopt);
|
||||||
Console.Error("Failed to save state");
|
});
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::saveStateToSlot(qint32 slot)
|
void EmuThread::saveStateToSlot(qint32 slot)
|
||||||
@ -347,7 +358,11 @@ void EmuThread::saveStateToSlot(qint32 slot)
|
|||||||
if (!VMManager::HasValidVM())
|
if (!VMManager::HasValidVM())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VMManager::SaveStateToSlot(slot);
|
VMManager::SaveStateToSlot(slot, true, [slot](const std::string& error) {
|
||||||
|
QtHost::RunOnUIThread([message = QString::fromStdString(error), slot]() {
|
||||||
|
g_main_window->reportStateSaveError(message, slot);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::run()
|
void EmuThread::run()
|
||||||
@ -1586,7 +1601,7 @@ bool QtHost::DownloadFile(QWidget* parent, const QString& title, std::string url
|
|||||||
!FileSystem::WriteBinaryFile(path.c_str(), data.data(), data.size()))
|
!FileSystem::WriteBinaryFile(path.c_str(), data.data(), data.size()))
|
||||||
{
|
{
|
||||||
QMessageBox::critical(parent, qApp->translate("EmuThread", "Error"),
|
QMessageBox::critical(parent, qApp->translate("EmuThread", "Error"),
|
||||||
qApp->translate("EmuThread", "Failed to write '%1'.").arg(QString::fromStdString(path)));
|
qApp->translate("EmuThread", "Failed to write downloaded data to file '%1'.").arg(QString::fromStdString(path)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -141,9 +141,16 @@ namespace QtUtils
|
|||||||
|
|
||||||
void resizeAndScalePixmap(QPixmap* pm, const int expected_width, const int expected_height, const qreal dpr, const ScalingMode scaling_mode, const float opacity)
|
void resizeAndScalePixmap(QPixmap* pm, const int expected_width, const int expected_height, const qreal dpr, const ScalingMode scaling_mode, const float opacity)
|
||||||
{
|
{
|
||||||
if (!pm || pm->isNull() || pm->width() <= 0 || pm->height() <= 0)
|
if (!pm || pm->width() <= 0 || pm->height() <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (dpr <= 0.0)
|
||||||
|
{
|
||||||
|
Console.ErrorFmt("resizeAndScalePixmap: Invalid device pixel ratio ({}) - pixmap will be null", dpr);
|
||||||
|
*pm = QPixmap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const int dpr_expected_width = qRound(expected_width * dpr);
|
const int dpr_expected_width = qRound(expected_width * dpr);
|
||||||
const int dpr_expected_height = qRound(expected_height * dpr);
|
const int dpr_expected_height = qRound(expected_height * dpr);
|
||||||
|
|
||||||
@ -196,8 +203,7 @@ namespace QtUtils
|
|||||||
qRound(scaledSize.width()),
|
qRound(scaledSize.width()),
|
||||||
qRound(scaledSize.height()),
|
qRound(scaledSize.height()),
|
||||||
Qt::IgnoreAspectRatio,
|
Qt::IgnoreAspectRatio,
|
||||||
Qt::SmoothTransformation
|
Qt::SmoothTransformation);
|
||||||
);
|
|
||||||
|
|
||||||
const QRectF scaledSrcRect(0, 0, pm->width(), pm->height());
|
const QRectF scaledSrcRect(0, 0, pm->width(), pm->height());
|
||||||
|
|
||||||
@ -211,16 +217,7 @@ namespace QtUtils
|
|||||||
}
|
}
|
||||||
case ScalingMode::Stretch:
|
case ScalingMode::Stretch:
|
||||||
{
|
{
|
||||||
*pm = pm->scaled(
|
painter.drawPixmap(painterRect, *pm, srcRect);
|
||||||
dpr_expected_width,
|
|
||||||
dpr_expected_height,
|
|
||||||
Qt::IgnoreAspectRatio,
|
|
||||||
Qt::SmoothTransformation
|
|
||||||
);
|
|
||||||
|
|
||||||
const QRectF scaledSrcRect(0, 0, pm->width(), pm->height());
|
|
||||||
|
|
||||||
painter.drawPixmap(painterRect, *pm, scaledSrcRect);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ScalingMode::Center:
|
case ScalingMode::Center:
|
||||||
@ -229,7 +226,6 @@ namespace QtUtils
|
|||||||
const qreal pmHeight = pm->height() / dpr;
|
const qreal pmHeight = pm->height() / dpr;
|
||||||
|
|
||||||
QRectF destRect(0, 0, pmWidth, pmHeight);
|
QRectF destRect(0, 0, pmWidth, pmHeight);
|
||||||
|
|
||||||
destRect.moveCenter(painterRect.center());
|
destRect.moveCenter(painterRect.center());
|
||||||
|
|
||||||
painter.drawPixmap(destRect, *pm, srcRect);
|
painter.drawPixmap(destRect, *pm, srcRect);
|
||||||
@ -243,13 +239,19 @@ namespace QtUtils
|
|||||||
if (tileWidth <= 0 || tileHeight <= 0)
|
if (tileWidth <= 0 || tileHeight <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
QPixmap tileSource = pm->scaled(tileWidth, tileHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
if (pm->devicePixelRatio() == dpr)
|
||||||
tileSource.setDevicePixelRatio(dpr);
|
{
|
||||||
|
QBrush tileBrush(*pm);
|
||||||
QBrush tileBrush(tileSource);
|
painter.fillRect(painterRect, tileBrush);
|
||||||
tileBrush.setTextureImage(tileSource.toImage());
|
}
|
||||||
|
else
|
||||||
painter.fillRect(painterRect, tileBrush);
|
{
|
||||||
|
QPixmap tileSource = pm->scaled(tileWidth, tileHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
tileSource.setDevicePixelRatio(dpr);
|
||||||
|
QBrush tileBrush(tileSource);
|
||||||
|
tileBrush.setTextureImage(tileSource.toImage());
|
||||||
|
painter.fillRect(painterRect, tileBrush);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -285,12 +287,12 @@ namespace QtUtils
|
|||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
//: Windows action to show a file in Windows Explorer
|
//: Windows action to show a file in Windows Explorer
|
||||||
return QCoreApplication::translate("FileOperations", "Show in Folder");
|
return QCoreApplication::translate("FileOperations", "Show in Explorer");
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
//: macOS action to show a file in Finder
|
//: macOS action to show a file in Finder
|
||||||
return QCoreApplication::translate("FileOperations", "Show in Finder");
|
return QCoreApplication::translate("FileOperations", "Show in Finder");
|
||||||
#else
|
#else
|
||||||
//: Opens the system file manager to the directory containing a selected file
|
//: Linux/*NIX: Opens the system file manager to the directory containing a selected file
|
||||||
return QCoreApplication::translate("FileOperations", "Open Containing Directory");
|
return QCoreApplication::translate("FileOperations", "Open Containing Directory");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1263,7 +1263,7 @@ namespace SettingWidgetBinder
|
|||||||
|
|
||||||
static inline void BindWidgetToFileSetting(SettingsInterface* sif, QLineEdit* widget, QAbstractButton* browse_button,
|
static inline void BindWidgetToFileSetting(SettingsInterface* sif, QLineEdit* widget, QAbstractButton* browse_button,
|
||||||
QAbstractButton* open_button, QAbstractButton* reset_button, std::string section, std::string key, std::string default_value,
|
QAbstractButton* open_button, QAbstractButton* reset_button, std::string section, std::string key, std::string default_value,
|
||||||
const char* filter, bool allow_pergame = false, bool use_relative = true)
|
const QString& filter, bool allow_pergame = false, bool use_relative = true)
|
||||||
{
|
{
|
||||||
using Accessor = SettingAccessor<QLineEdit>;
|
using Accessor = SettingAccessor<QLineEdit>;
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
#include <QtCore/QDateTime>
|
#include <QtCore/QDateTime>
|
||||||
#include <QtWidgets/QMessageBox>
|
#include <QtWidgets/QMessageBox>
|
||||||
|
|
||||||
const char* AUDIO_FILE_FILTER = QT_TRANSLATE_NOOP("MainWindow", "Audio Files (*.wav)");
|
const char* AchievementSettingsWidget::AUDIO_FILE_FILTER = QT_TRANSLATE_NOOP("AchievementSettingsWidget", "WAV Audio Files (*.wav)");
|
||||||
|
|
||||||
AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* settings_dialog, QWidget* parent)
|
AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* settings_dialog, QWidget* parent)
|
||||||
: SettingsWidget(settings_dialog, parent)
|
: SettingsWidget(settings_dialog, parent)
|
||||||
@ -44,9 +44,9 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* settings_di
|
|||||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.achievementNotificationsDuration, "Achievements", "NotificationsDuration", Pcsx2Config::AchievementsOptions::DEFAULT_NOTIFICATION_DURATION);
|
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.achievementNotificationsDuration, "Achievements", "NotificationsDuration", Pcsx2Config::AchievementsOptions::DEFAULT_NOTIFICATION_DURATION);
|
||||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.leaderboardNotificationsDuration, "Achievements", "LeaderboardsDuration", Pcsx2Config::AchievementsOptions::DEFAULT_LEADERBOARD_DURATION);
|
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.leaderboardNotificationsDuration, "Achievements", "LeaderboardsDuration", Pcsx2Config::AchievementsOptions::DEFAULT_LEADERBOARD_DURATION);
|
||||||
|
|
||||||
SettingWidgetBinder::BindWidgetToFileSetting(sif, m_ui.notificationSoundPath, m_ui.notificationSoundBrowse, m_ui.notificationSoundOpen, m_ui.notificationSoundReset, "Achievements", "InfoSoundName", Path::Combine(EmuFolders::Resources, EmuConfig.Achievements.DEFAULT_INFO_SOUND_NAME), AUDIO_FILE_FILTER, true, false);
|
SettingWidgetBinder::BindWidgetToFileSetting(sif, m_ui.notificationSoundPath, m_ui.notificationSoundBrowse, m_ui.notificationSoundOpen, m_ui.notificationSoundReset, "Achievements", "InfoSoundName", Path::Combine(EmuFolders::Resources, EmuConfig.Achievements.DEFAULT_INFO_SOUND_NAME), qApp->translate("AchievementSettingsWidget", AUDIO_FILE_FILTER), true, false);
|
||||||
SettingWidgetBinder::BindWidgetToFileSetting(sif, m_ui.unlockSoundPath, m_ui.unlockSoundBrowse, m_ui.unlockSoundOpen, m_ui.unlockSoundReset, "Achievements", "UnlockSoundName", Path::Combine(EmuFolders::Resources, EmuConfig.Achievements.DEFAULT_UNLOCK_SOUND_NAME), AUDIO_FILE_FILTER, true, false);
|
SettingWidgetBinder::BindWidgetToFileSetting(sif, m_ui.unlockSoundPath, m_ui.unlockSoundBrowse, m_ui.unlockSoundOpen, m_ui.unlockSoundReset, "Achievements", "UnlockSoundName", Path::Combine(EmuFolders::Resources, EmuConfig.Achievements.DEFAULT_UNLOCK_SOUND_NAME), qApp->translate("AchievementSettingsWidget", AUDIO_FILE_FILTER), true, false);
|
||||||
SettingWidgetBinder::BindWidgetToFileSetting(sif, m_ui.lbSoundPath, m_ui.lbSoundBrowse, m_ui.lbSoundOpen, m_ui.lbSoundReset, "Achievements", "LBSubmitSoundName", Path::Combine(EmuFolders::Resources, EmuConfig.Achievements.DEFAULT_LBSUBMIT_SOUND_NAME), AUDIO_FILE_FILTER, true, false);
|
SettingWidgetBinder::BindWidgetToFileSetting(sif, m_ui.lbSoundPath, m_ui.lbSoundBrowse, m_ui.lbSoundOpen, m_ui.lbSoundReset, "Achievements", "LBSubmitSoundName", Path::Combine(EmuFolders::Resources, EmuConfig.Achievements.DEFAULT_LBSUBMIT_SOUND_NAME), qApp->translate("AchievementSettingsWidget", AUDIO_FILE_FILTER), true, false);
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_ui.enable, tr("Enable Achievements"), tr("Unchecked"), tr("When enabled and logged in, PCSX2 will scan for achievements on startup."));
|
dialog()->registerWidgetHelp(m_ui.enable, tr("Enable Achievements"), tr("Unchecked"), tr("When enabled and logged in, PCSX2 will scan for achievements on startup."));
|
||||||
dialog()->registerWidgetHelp(m_ui.hardcoreMode, tr("Enable Hardcore Mode"), tr("Unchecked"), tr("\"Challenge\" mode for achievements, including leaderboard tracking. Disables save state, cheats, and slowdown functions."));
|
dialog()->registerWidgetHelp(m_ui.hardcoreMode, tr("Enable Hardcore Mode"), tr("Unchecked"), tr("\"Challenge\" mode for achievements, including leaderboard tracking. Disables save state, cheats, and slowdown functions."));
|
||||||
|
|||||||
@ -26,6 +26,7 @@ private Q_SLOTS:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void updateLoginState();
|
void updateLoginState();
|
||||||
|
static const char* AUDIO_FILE_FILTER;
|
||||||
|
|
||||||
Ui::AchievementSettingsWidget m_ui;
|
Ui::AchievementSettingsWidget m_ui;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -115,7 +115,7 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsWindow* settings_dialog, QWidge
|
|||||||
dialog()->registerWidgetHelp(m_ui.expansionSettings, tr("Expansion Settings"), tr("N/A"),
|
dialog()->registerWidgetHelp(m_ui.expansionSettings, tr("Expansion Settings"), tr("N/A"),
|
||||||
tr("These settings fine-tune the behavior of the FreeSurround-based channel expander."));
|
tr("These settings fine-tune the behavior of the FreeSurround-based channel expander."));
|
||||||
dialog()->registerWidgetHelp(m_ui.syncMode, tr("Synchronization"), tr("TimeStretch (Recommended)"),
|
dialog()->registerWidgetHelp(m_ui.syncMode, tr("Synchronization"), tr("TimeStretch (Recommended)"),
|
||||||
tr("When running outside of 100% speed, adjusts the tempo on audio instead of dropping frames. Produces much nicer fast-forward/slowdown audio."));
|
tr("When the emulation isn't running at 100% speed, adjusts the tempo of the audio which produces much nicer sound during fast-forward/slowdown."));
|
||||||
dialog()->registerWidgetHelp(m_ui.stretchSettings, tr("Stretch Settings"), tr("N/A"),
|
dialog()->registerWidgetHelp(m_ui.stretchSettings, tr("Stretch Settings"), tr("N/A"),
|
||||||
tr("These settings fine-tune the behavior of the SoundTouch audio time stretcher when running outside of 100% speed."));
|
tr("These settings fine-tune the behavior of the SoundTouch audio time stretcher when running outside of 100% speed."));
|
||||||
dialog()->registerWidgetHelp(m_ui.resetStandardVolume, tr("Reset Standard Volume"), tr("N/A"),
|
dialog()->registerWidgetHelp(m_ui.resetStandardVolume, tr("Reset Standard Volume"), tr("N/A"),
|
||||||
@ -180,7 +180,7 @@ void AudioSettingsWidget::updateDriverNames()
|
|||||||
const AudioBackend backend = getEffectiveBackend();
|
const AudioBackend backend = getEffectiveBackend();
|
||||||
const std::vector<std::pair<std::string, std::string>> names = AudioStream::GetDriverNames(backend);
|
const std::vector<std::pair<std::string, std::string>> names = AudioStream::GetDriverNames(backend);
|
||||||
|
|
||||||
m_ui.driver->disconnect();
|
QObject::disconnect(m_ui.driver, &QComboBox::currentIndexChanged, nullptr, nullptr);
|
||||||
m_ui.driver->clear();
|
m_ui.driver->clear();
|
||||||
if (names.empty())
|
if (names.empty())
|
||||||
{
|
{
|
||||||
@ -208,7 +208,7 @@ void AudioSettingsWidget::updateDeviceNames()
|
|||||||
const std::string current_device = dialog()->getEffectiveStringValue("SPU2/Output", "DeviceName", "");
|
const std::string current_device = dialog()->getEffectiveStringValue("SPU2/Output", "DeviceName", "");
|
||||||
const std::vector<AudioStream::DeviceInfo> devices = AudioStream::GetOutputDevices(backend, driver_name.c_str());
|
const std::vector<AudioStream::DeviceInfo> devices = AudioStream::GetOutputDevices(backend, driver_name.c_str());
|
||||||
|
|
||||||
m_ui.outputDevice->disconnect();
|
QObject::disconnect(m_ui.outputDevice, &QComboBox::currentIndexChanged, nullptr, nullptr);
|
||||||
m_ui.outputDevice->clear();
|
m_ui.outputDevice->clear();
|
||||||
m_output_device_latency = 0;
|
m_output_device_latency = 0;
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,8 @@ BIOSSettingsWidget::BIOSSettingsWidget(SettingsWindow* settings_dialog, QWidget*
|
|||||||
connect(m_ui.refresh, &QPushButton::clicked, this, &BIOSSettingsWidget::refreshList);
|
connect(m_ui.refresh, &QPushButton::clicked, this, &BIOSSettingsWidget::refreshList);
|
||||||
connect(m_ui.fileList, &QTreeWidget::currentItemChanged, this, &BIOSSettingsWidget::listItemChanged);
|
connect(m_ui.fileList, &QTreeWidget::currentItemChanged, this, &BIOSSettingsWidget::listItemChanged);
|
||||||
connect(m_ui.fastBoot, &QCheckBox::checkStateChanged, this, &BIOSSettingsWidget::fastBootChanged);
|
connect(m_ui.fastBoot, &QCheckBox::checkStateChanged, this, &BIOSSettingsWidget::fastBootChanged);
|
||||||
|
|
||||||
|
fastBootChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
BIOSSettingsWidget::~BIOSSettingsWidget() = default;
|
BIOSSettingsWidget::~BIOSSettingsWidget() = default;
|
||||||
|
|||||||
@ -30,7 +30,7 @@ DEV9DnsHostDialog::DEV9DnsHostDialog(std::vector<HostEntryUi> hosts, QWidget* pa
|
|||||||
QStringList headers;
|
QStringList headers;
|
||||||
headers.push_back(tr("Selected"));
|
headers.push_back(tr("Selected"));
|
||||||
headers.push_back(tr("Name"));
|
headers.push_back(tr("Name"));
|
||||||
headers.push_back(tr("Url"));
|
headers.push_back(tr("Hostname"));
|
||||||
headers.push_back(tr("Address"));
|
headers.push_back(tr("Address"));
|
||||||
headers.push_back(tr("Enabled"));
|
headers.push_back(tr("Enabled"));
|
||||||
m_ethHost_model->setHorizontalHeaderLabels(headers);
|
m_ethHost_model->setHorizontalHeaderLabels(headers);
|
||||||
|
|||||||
@ -139,7 +139,7 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsWindow* settings_dialog, QWidget*
|
|||||||
|
|
||||||
QStringList headers;
|
QStringList headers;
|
||||||
headers.push_back(tr("Name"));
|
headers.push_back(tr("Name"));
|
||||||
headers.push_back(tr("Url"));
|
headers.push_back(tr("Hostname"));
|
||||||
headers.push_back(tr("Address"));
|
headers.push_back(tr("Address"));
|
||||||
headers.push_back(tr("Enabled"));
|
headers.push_back(tr("Enabled"));
|
||||||
m_ethHost_model->setHorizontalHeaderLabels(headers);
|
m_ethHost_model->setHorizontalHeaderLabels(headers);
|
||||||
@ -792,7 +792,7 @@ void DEV9SettingsWidget::showEvent(QShowEvent* event)
|
|||||||
* hidden, maybe because our table is nested within group & tab widgets
|
* hidden, maybe because our table is nested within group & tab widgets
|
||||||
* We could also listern to out show event, but we also need to listern to the tab
|
* We could also listern to out show event, but we also need to listern to the tab
|
||||||
* changed signal, in the event that another tab is selected when our ui is shown
|
* changed signal, in the event that another tab is selected when our ui is shown
|
||||||
*
|
*
|
||||||
* Instead, lets use an eventFilter to determine exactly when the host table is shown
|
* Instead, lets use an eventFilter to determine exactly when the host table is shown
|
||||||
* However, the eventFilter is ran before the widgets event handler, meaning the table
|
* However, the eventFilter is ran before the widgets event handler, meaning the table
|
||||||
* is still the wrong size, so we also need to check the show event
|
* is still the wrong size, so we also need to check the show event
|
||||||
|
|||||||
@ -83,7 +83,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="symbolSourceErrorMessage">
|
<widget class="QLabel" name="symbolSourceErrorMessage">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><html><head/><body><p><br/></p></body></html></string>
|
<string notr="true"><html><head/><body><p><br/></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||||
|
|||||||
@ -40,6 +40,9 @@ GameCheatSettingsWidget::GameCheatSettingsWidget(SettingsWindow* settings_dialog
|
|||||||
|
|
||||||
m_ui.cheatList->expandAll();
|
m_ui.cheatList->expandAll();
|
||||||
|
|
||||||
|
m_ui.cheatList->viewport()->installEventFilter(this);
|
||||||
|
m_ui.cheatList->viewport()->setMouseTracking(true);
|
||||||
|
|
||||||
SettingsInterface* sif = dialog()->getSettingsInterface();
|
SettingsInterface* sif = dialog()->getSettingsInterface();
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableCheats, "EmuCore", "EnableCheats", false);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableCheats, "EmuCore", "EnableCheats", false);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.allCRCsCheckbox, "EmuCore", "ShowCheatsForAllCRCs", false);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.allCRCsCheckbox, "EmuCore", "ShowCheatsForAllCRCs", false);
|
||||||
@ -83,7 +86,7 @@ void GameCheatSettingsWidget::onCheatListItemDoubleClicked(const QModelIndex& in
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant data = item->data(Qt::UserRole);
|
QVariant data = item->data(NAME_ROLE);
|
||||||
if (!data.isValid())
|
if (!data.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -95,7 +98,7 @@ void GameCheatSettingsWidget::onCheatListItemDoubleClicked(const QModelIndex& in
|
|||||||
|
|
||||||
void GameCheatSettingsWidget::onCheatListItemChanged(QStandardItem* item)
|
void GameCheatSettingsWidget::onCheatListItemChanged(QStandardItem* item)
|
||||||
{
|
{
|
||||||
QVariant data = item->data(Qt::UserRole);
|
QVariant data = item->data(NAME_ROLE);
|
||||||
if (!data.isValid())
|
if (!data.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -109,6 +112,31 @@ void GameCheatSettingsWidget::onCheatListItemChanged(QStandardItem* item)
|
|||||||
setCheatEnabled(std::move(cheat_name), current_checked, true);
|
setCheatEnabled(std::move(cheat_name), current_checked, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameCheatSettingsWidget::onCheatListItemHovered(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
const QModelIndex source_index = m_model_proxy->mapToSource(index);
|
||||||
|
const QModelIndex sibling_index = source_index.siblingAtColumn(0);
|
||||||
|
QStandardItem* item = m_model->itemFromIndex(sibling_index);
|
||||||
|
if (!item)
|
||||||
|
{
|
||||||
|
// No item is selected.
|
||||||
|
m_ui.appliedLabel->clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Patch::patch_place_type> place;
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
int place_value = item->data(PLACE_ROLE).toInt(&ok);
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
// The patch commands in the group are all applied at the same time.
|
||||||
|
place = static_cast<Patch::patch_place_type>(place_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ui.appliedLabel->setText(tr("<strong>Applied:</strong> %1").arg(Patch::PlaceToString(place)));
|
||||||
|
}
|
||||||
|
|
||||||
void GameCheatSettingsWidget::onReloadClicked()
|
void GameCheatSettingsWidget::onReloadClicked()
|
||||||
{
|
{
|
||||||
reloadList();
|
reloadList();
|
||||||
@ -136,6 +164,32 @@ void GameCheatSettingsWidget::disableAllCheats()
|
|||||||
si->Save();
|
si->Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GameCheatSettingsWidget::eventFilter(QObject* watched, QEvent* event)
|
||||||
|
{
|
||||||
|
if (watched == m_ui.cheatList->viewport())
|
||||||
|
{
|
||||||
|
switch (event->type())
|
||||||
|
{
|
||||||
|
case QEvent::MouseMove:
|
||||||
|
{
|
||||||
|
QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
|
||||||
|
onCheatListItemHovered(m_ui.cheatList->indexAt(mouse_event->position().toPoint()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case QEvent::Leave:
|
||||||
|
{
|
||||||
|
onCheatListItemHovered(QModelIndex());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SettingsWidget::eventFilter(watched, event);
|
||||||
|
}
|
||||||
|
|
||||||
void GameCheatSettingsWidget::resizeEvent(QResizeEvent* event)
|
void GameCheatSettingsWidget::resizeEvent(QResizeEvent* event)
|
||||||
{
|
{
|
||||||
QWidget::resizeEvent(event);
|
QWidget::resizeEvent(event);
|
||||||
@ -185,7 +239,7 @@ void GameCheatSettingsWidget::setStateRecursively(QStandardItem* parent, bool en
|
|||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
QStandardItem* item = parent ? parent->child(i, 0) : m_model->item(i, 0);
|
QStandardItem* item = parent ? parent->child(i, 0) : m_model->item(i, 0);
|
||||||
QVariant data = item->data(Qt::UserRole);
|
QVariant data = item->data(NAME_ROLE);
|
||||||
if (data.isValid())
|
if (data.isValid())
|
||||||
{
|
{
|
||||||
if ((item->checkState() == Qt::Checked) != enabled)
|
if ((item->checkState() == Qt::Checked) != enabled)
|
||||||
@ -277,7 +331,9 @@ QList<QStandardItem*> GameCheatSettingsWidget::populateTreeViewRow(const Patch::
|
|||||||
const std::string_view name_part = pi.GetNamePart();
|
const std::string_view name_part = pi.GetNamePart();
|
||||||
nameItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren | Qt::ItemIsEnabled);
|
nameItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren | Qt::ItemIsEnabled);
|
||||||
nameItem->setCheckState(enabled ? Qt::Checked : Qt::Unchecked);
|
nameItem->setCheckState(enabled ? Qt::Checked : Qt::Unchecked);
|
||||||
nameItem->setData(QString::fromStdString(pi.name), Qt::UserRole);
|
nameItem->setData(QString::fromStdString(pi.name), NAME_ROLE);
|
||||||
|
if (pi.place.has_value())
|
||||||
|
nameItem->setData(static_cast<int>(*pi.place), PLACE_ROLE);
|
||||||
if (!name_part.empty())
|
if (!name_part.empty())
|
||||||
nameItem->setText(QString::fromUtf8(name_part.data(), name_part.length()));
|
nameItem->setText(QString::fromUtf8(name_part.data(), name_part.length()));
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,7 @@ public:
|
|||||||
~GameCheatSettingsWidget();
|
~GameCheatSettingsWidget();
|
||||||
|
|
||||||
void disableAllCheats();
|
void disableAllCheats();
|
||||||
|
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent* event) override;
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
@ -39,6 +40,7 @@ protected:
|
|||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onCheatListItemDoubleClicked(const QModelIndex& index);
|
void onCheatListItemDoubleClicked(const QModelIndex& index);
|
||||||
void onCheatListItemChanged(QStandardItem* item);
|
void onCheatListItemChanged(QStandardItem* item);
|
||||||
|
void onCheatListItemHovered(const QModelIndex& index);
|
||||||
void onReloadClicked();
|
void onReloadClicked();
|
||||||
void updateListEnabled();
|
void updateListEnabled();
|
||||||
void reloadList();
|
void reloadList();
|
||||||
@ -50,6 +52,12 @@ private:
|
|||||||
void setStateForAll(bool enabled);
|
void setStateForAll(bool enabled);
|
||||||
void setStateRecursively(QStandardItem* parent, bool enabled);
|
void setStateRecursively(QStandardItem* parent, bool enabled);
|
||||||
|
|
||||||
|
enum Roles
|
||||||
|
{
|
||||||
|
NAME_ROLE = Qt::UserRole,
|
||||||
|
PLACE_ROLE = Qt::UserRole + 1
|
||||||
|
};
|
||||||
|
|
||||||
Ui::GameCheatSettingsWidget m_ui;
|
Ui::GameCheatSettingsWidget m_ui;
|
||||||
QStandardItemModel* m_model = nullptr;
|
QStandardItemModel* m_model = nullptr;
|
||||||
QSortFilterProxyModel* m_model_proxy = nullptr;
|
QSortFilterProxyModel* m_model_proxy = nullptr;
|
||||||
|
|||||||
@ -90,6 +90,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="appliedLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|||||||
@ -44,7 +44,7 @@ GameFixSettingsWidget::GameFixSettingsWidget(SettingsWindow* settings_dialog, QW
|
|||||||
dialog()->registerWidgetHelp(m_ui.EETimingHack, tr("EE Timing Hack"), tr("Unchecked"), tr("General-purpose timing hack. Known to affect following games: Digital Devil Saga, SSX."));
|
dialog()->registerWidgetHelp(m_ui.EETimingHack, tr("EE Timing Hack"), tr("Unchecked"), tr("General-purpose timing hack. Known to affect following games: Digital Devil Saga, SSX."));
|
||||||
dialog()->registerWidgetHelp(m_ui.InstantDMAHack, tr("Instant DMA Hack"), tr("Unchecked"), tr("Good for cache emulation problems. Known to affect following games: Fire Pro Wrestling Z."));
|
dialog()->registerWidgetHelp(m_ui.InstantDMAHack, tr("Instant DMA Hack"), tr("Unchecked"), tr("Good for cache emulation problems. Known to affect following games: Fire Pro Wrestling Z."));
|
||||||
dialog()->registerWidgetHelp(m_ui.DMABusyHack, tr("DMA Busy Hack"), tr("Unchecked"), tr("Known to affect following games: Mana Khemia 1, Metal Saga, Pilot Down Behind Enemy Lines."));
|
dialog()->registerWidgetHelp(m_ui.DMABusyHack, tr("DMA Busy Hack"), tr("Unchecked"), tr("Known to affect following games: Mana Khemia 1, Metal Saga, Pilot Down Behind Enemy Lines."));
|
||||||
dialog()->registerWidgetHelp(m_ui.GIFFIFOHack, tr("Emulate GIF FIFO"), tr("Unchecked"), tr("Correct but slower. Known to affect the following games: Fifa Street 2."));
|
dialog()->registerWidgetHelp(m_ui.GIFFIFOHack, tr("Emulate GIF FIFO"), tr("Unchecked"), tr("Correct but slower. Known to affect the following games: FIFA Street 2."));
|
||||||
dialog()->registerWidgetHelp(m_ui.VIFFIFOHack, tr("Emulate VIF FIFO"), tr("Unchecked"), tr("Simulate VIF1 FIFO read ahead. Known to affect following games: Test Drive Unlimited, Transformers."));
|
dialog()->registerWidgetHelp(m_ui.VIFFIFOHack, tr("Emulate VIF FIFO"), tr("Unchecked"), tr("Simulate VIF1 FIFO read ahead. Known to affect following games: Test Drive Unlimited, Transformers."));
|
||||||
dialog()->registerWidgetHelp(m_ui.VIF1StallHack, tr("Delay VIF1 Stalls"), tr("Unchecked"), tr("For SOCOM 2 HUD and Spy Hunter loading hang."));
|
dialog()->registerWidgetHelp(m_ui.VIF1StallHack, tr("Delay VIF1 Stalls"), tr("Unchecked"), tr("For SOCOM 2 HUD and Spy Hunter loading hang."));
|
||||||
dialog()->registerWidgetHelp(m_ui.VuAddSubHack, tr("VU Add Hack"), tr("Unchecked"), tr("For Tri-Ace Games: Star Ocean 3, Radiata Stories, Valkyrie Profile 2."));
|
dialog()->registerWidgetHelp(m_ui.VuAddSubHack, tr("VU Add Hack"), tr("Unchecked"), tr("For Tri-Ace Games: Star Ocean 3, Radiata Stories, Valkyrie Profile 2."));
|
||||||
|
|||||||
@ -15,19 +15,23 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
GamePatchDetailsWidget::GamePatchDetailsWidget(std::string name, const std::string& author,
|
GamePatchDetailsWidget::GamePatchDetailsWidget(const Patch::PatchInfo& info, bool tristate, Qt::CheckState checkState, SettingsWindow* dialog, QWidget* parent)
|
||||||
const std::string& description, bool tristate, Qt::CheckState checkState, SettingsWindow* dialog, QWidget* parent)
|
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, m_dialog(dialog)
|
, m_dialog(dialog)
|
||||||
, m_name(name)
|
, m_name(info.name)
|
||||||
{
|
{
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
||||||
m_ui.name->setText(QString::fromStdString(name));
|
const QString name = QString::fromStdString(info.name);
|
||||||
|
const QString author = !info.author.empty() ? QString::fromStdString(info.author) : tr("Unknown");
|
||||||
|
const QString place = QString::fromUtf8(PlaceToString(info.place));
|
||||||
|
const QString description = !info.description.empty() ? QString::fromStdString(info.description) : tr("No description provided.");
|
||||||
|
m_ui.name->setText(name);
|
||||||
m_ui.description->setText(
|
m_ui.description->setText(
|
||||||
tr("<strong>Author: </strong>%1<br>%2")
|
tr("<strong>Author:</strong> %1<br><strong>Applied:</strong> %2<br>%3")
|
||||||
.arg(author.empty() ? tr("Unknown") : QString::fromStdString(author))
|
.arg(author)
|
||||||
.arg(description.empty() ? tr("No description provided.") : QString::fromStdString(description)));
|
.arg(place)
|
||||||
|
.arg(description));
|
||||||
|
|
||||||
pxAssert(dialog->getSettingsInterface());
|
pxAssert(dialog->getSettingsInterface());
|
||||||
m_ui.enabled->setTristate(tristate);
|
m_ui.enabled->setTristate(tristate);
|
||||||
@ -178,7 +182,7 @@ void GamePatchSettingsWidget::reloadList()
|
|||||||
}
|
}
|
||||||
|
|
||||||
GamePatchDetailsWidget* it =
|
GamePatchDetailsWidget* it =
|
||||||
new GamePatchDetailsWidget(std::move(pi.name), pi.author, pi.description, globally_toggleable_option, check_state, dialog(), container);
|
new GamePatchDetailsWidget(pi, globally_toggleable_option, check_state, dialog(), container);
|
||||||
layout->addWidget(it);
|
layout->addWidget(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ class GamePatchDetailsWidget : public QWidget
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GamePatchDetailsWidget(std::string name, const std::string& author, const std::string& description, bool tristate, Qt::CheckState checkState,
|
GamePatchDetailsWidget(const Patch::PatchInfo& info, bool tristate, Qt::CheckState checkState,
|
||||||
SettingsWindow* dialog, QWidget* parent);
|
SettingsWindow* dialog, QWidget* parent);
|
||||||
~GamePatchDetailsWidget();
|
~GamePatchDetailsWidget();
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="screenshotGroupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Screenshot Capture Setup</string>
|
<string>Screenshot Capture Setup</string>
|
||||||
</property>
|
</property>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Window Resolution (Aspect Corrected)</string>
|
<string>Display Resolution (Aspect Corrected)</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -186,6 +186,9 @@
|
|||||||
<property name="singleStep">
|
<property name="singleStep">
|
||||||
<number>1</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>67</number>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" colspan="2">
|
<item row="2" column="0" colspan="2">
|
||||||
@ -273,6 +276,9 @@
|
|||||||
<property name="singleStep">
|
<property name="singleStep">
|
||||||
<number>100</number>
|
<number>100</number>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>420</number>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="0">
|
||||||
@ -325,7 +331,7 @@
|
|||||||
<number>16</number>
|
<number>16</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<number>240</number>
|
<number>480</number>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@ -472,7 +472,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
|
|||||||
|
|
||||||
dialog()->registerWidgetHelp(m_display.interlacing, tr("Deinterlacing"), tr("Automatic (Default)"), tr("Determines the deinterlacing method to be used on the interlaced screen of the emulated console. Automatic should be able to correctly deinterlace most games, but if you see visibly shaky graphics, try one of the other options."));
|
dialog()->registerWidgetHelp(m_display.interlacing, tr("Deinterlacing"), tr("Automatic (Default)"), tr("Determines the deinterlacing method to be used on the interlaced screen of the emulated console. Automatic should be able to correctly deinterlace most games, but if you see visibly shaky graphics, try one of the other options."));
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_capture.screenshotSize, tr("Screenshot Resolution"), tr("Screen Resolution"),
|
dialog()->registerWidgetHelp(m_capture.screenshotSize, tr("Screenshot Resolution"), tr("Display Resolution"),
|
||||||
tr("Determines the resolution at which screenshots will be saved. Internal resolutions preserve more detail at the cost of "
|
tr("Determines the resolution at which screenshots will be saved. Internal resolutions preserve more detail at the cost of "
|
||||||
"file size."));
|
"file size."));
|
||||||
|
|
||||||
@ -587,10 +587,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
|
|||||||
dialog()->registerWidgetHelp(m_fixes.gpuTargetCLUTMode, tr("GPU Target CLUT"), tr("Disabled"),
|
dialog()->registerWidgetHelp(m_fixes.gpuTargetCLUTMode, tr("GPU Target CLUT"), tr("Disabled"),
|
||||||
tr("Tries to detect when a game is drawing its own color palette and then renders it on the GPU with special handling."));
|
tr("Tries to detect when a game is drawing its own color palette and then renders it on the GPU with special handling."));
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_fixes.skipDrawStart, tr("Skipdraw Range Start"), tr("0"),
|
dialog()->registerWidgetHelp(m_fixes.skipDrawStart, tr("Skip Draw Range Start"), tr("0"),
|
||||||
tr("Completely skips drawing surfaces from the surface in the left box up to the surface specified in the box on the right."));
|
tr("Completely skips drawing surfaces from the surface in the left box up to the surface specified in the box on the right."));
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_fixes.skipDrawEnd, tr("Skipdraw Range End"), tr("0"),
|
dialog()->registerWidgetHelp(m_fixes.skipDrawEnd, tr("Skip Draw Range End"), tr("0"),
|
||||||
tr("Completely skips drawing surfaces from the surface in the left box up to the surface specified in the box on the right."));
|
tr("Completely skips drawing surfaces from the surface in the left box up to the surface specified in the box on the right."));
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_fixes.hwAutoFlush, tr("Auto Flush"), tr("Unchecked"),
|
dialog()->registerWidgetHelp(m_fixes.hwAutoFlush, tr("Auto Flush"), tr("Unchecked"),
|
||||||
@ -660,7 +660,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
|
|||||||
//: Wild Arms: name of a game series. Leave as-is or use an official translation.
|
//: Wild Arms: name of a game series. Leave as-is or use an official translation.
|
||||||
tr("Lowers the GS precision to avoid gaps between pixels when upscaling. Fixes the text on Wild Arms games."));
|
tr("Lowers the GS precision to avoid gaps between pixels when upscaling. Fixes the text on Wild Arms games."));
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_upscaling.bilinearHack, tr("Bilinear Upscale"), tr("Unchecked"),
|
dialog()->registerWidgetHelp(m_upscaling.bilinearHack, tr("Bilinear Dirty Upscale"), tr("Unchecked"),
|
||||||
tr("Can smooth out textures due to be bilinear filtered when upscaling. E.g. Brave sun glare."));
|
tr("Can smooth out textures due to be bilinear filtered when upscaling. E.g. Brave sun glare."));
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_upscaling.mergeSprite, tr("Merge Sprite"), tr("Unchecked"),
|
dialog()->registerWidgetHelp(m_upscaling.mergeSprite, tr("Merge Sprite"), tr("Unchecked"),
|
||||||
@ -729,7 +729,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
|
|||||||
tr("Shows the number of internal video frames displayed per second by the system."));
|
tr("Shows the number of internal video frames displayed per second by the system."));
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_osd.showVPS, tr("Show VPS"), tr("Unchecked"),
|
dialog()->registerWidgetHelp(m_osd.showVPS, tr("Show VPS"), tr("Unchecked"),
|
||||||
tr("Shows the number of V-syncs performed per second by the system."));
|
tr("Shows the number of Vsyncs performed per second by the system."));
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_osd.showResolution, tr("Show Resolution"), tr("Unchecked"),
|
dialog()->registerWidgetHelp(m_osd.showResolution, tr("Show Resolution"), tr("Unchecked"),
|
||||||
tr("Shows the internal resolution of the game."));
|
tr("Shows the internal resolution of the game."));
|
||||||
@ -765,10 +765,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
|
|||||||
tr("Shows the current controller state of the system in the bottom-left corner of the display."));
|
tr("Shows the current controller state of the system in the bottom-left corner of the display."));
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_osd.showVideoCapture, tr("Show Video Capture Status"), tr("Checked"),
|
dialog()->registerWidgetHelp(m_osd.showVideoCapture, tr("Show Video Capture Status"), tr("Checked"),
|
||||||
tr("Shows the status of the currently active video capture in the top-right corner of the display.."));
|
tr("Shows the status of the currently active video capture in the top-right corner of the display."));
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_osd.showInputRec, tr("Show Input Recording Status"), tr("Checked"),
|
dialog()->registerWidgetHelp(m_osd.showInputRec, tr("Show Input Recording Status"), tr("Checked"),
|
||||||
tr("Shows the status of the currently active input recording in the top-right corner of the display.."));
|
tr("Shows the status of the currently active input recording in the top-right corner of the display."));
|
||||||
|
|
||||||
dialog()->registerWidgetHelp(m_osd.showTextureReplacements, tr("Show Texture Replacement Status"), tr("Unchecked"),
|
dialog()->registerWidgetHelp(m_osd.showTextureReplacements, tr("Show Texture Replacement Status"), tr("Unchecked"),
|
||||||
tr("Shows the status of the number of dumped and loaded texture replacements in the top-right corner of the display."));
|
tr("Shows the status of the number of dumped and loaded texture replacements in the top-right corner of the display."));
|
||||||
@ -981,7 +981,7 @@ void GraphicsSettingsWidget::onCaptureContainerChanged()
|
|||||||
const std::string container(
|
const std::string container(
|
||||||
dialog()->getEffectiveStringValue("EmuCore/GS", "CaptureContainer", Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER));
|
dialog()->getEffectiveStringValue("EmuCore/GS", "CaptureContainer", Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER));
|
||||||
|
|
||||||
m_capture.videoCaptureCodec->disconnect();
|
QObject::disconnect(m_capture.videoCaptureCodec, &QComboBox::currentIndexChanged, nullptr, nullptr);
|
||||||
m_capture.videoCaptureCodec->clear();
|
m_capture.videoCaptureCodec->clear();
|
||||||
//: This string refers to a default codec, whether it's an audio codec or a video codec.
|
//: This string refers to a default codec, whether it's an audio codec or a video codec.
|
||||||
m_capture.videoCaptureCodec->addItem(tr("Default"), QString());
|
m_capture.videoCaptureCodec->addItem(tr("Default"), QString());
|
||||||
@ -996,7 +996,7 @@ void GraphicsSettingsWidget::onCaptureContainerChanged()
|
|||||||
dialog()->getSettingsInterface(), m_capture.videoCaptureCodec, "EmuCore/GS", "VideoCaptureCodec");
|
dialog()->getSettingsInterface(), m_capture.videoCaptureCodec, "EmuCore/GS", "VideoCaptureCodec");
|
||||||
connect(m_capture.videoCaptureCodec, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onCaptureCodecChanged);
|
connect(m_capture.videoCaptureCodec, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onCaptureCodecChanged);
|
||||||
|
|
||||||
m_capture.audioCaptureCodec->disconnect();
|
QObject::disconnect(m_capture.audioCaptureCodec, &QComboBox::currentIndexChanged, nullptr, nullptr);
|
||||||
m_capture.audioCaptureCodec->clear();
|
m_capture.audioCaptureCodec->clear();
|
||||||
m_capture.audioCaptureCodec->addItem(tr("Default"), QString());
|
m_capture.audioCaptureCodec->addItem(tr("Default"), QString());
|
||||||
for (const auto& [format, name] : GSCapture::GetAudioCodecList(container.c_str()))
|
for (const auto& [format, name] : GSCapture::GetAudioCodecList(container.c_str()))
|
||||||
@ -1012,7 +1012,7 @@ void GraphicsSettingsWidget::onCaptureContainerChanged()
|
|||||||
|
|
||||||
void GraphicsSettingsWidget::GraphicsSettingsWidget::onCaptureCodecChanged()
|
void GraphicsSettingsWidget::GraphicsSettingsWidget::onCaptureCodecChanged()
|
||||||
{
|
{
|
||||||
m_capture.videoCaptureFormat->disconnect();
|
QObject::disconnect(m_capture.videoCaptureFormat, &QComboBox::currentIndexChanged, nullptr, nullptr);
|
||||||
m_capture.videoCaptureFormat->clear();
|
m_capture.videoCaptureFormat->clear();
|
||||||
//: This string refers to a default pixel format
|
//: This string refers to a default pixel format
|
||||||
m_capture.videoCaptureFormat->addItem(tr("Default"), "");
|
m_capture.videoCaptureFormat->addItem(tr("Default"), "");
|
||||||
|
|||||||
@ -93,7 +93,7 @@
|
|||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="nativeScalingLabel">
|
<widget class="QLabel" name="nativeScalingLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Native Scaling</string>
|
<string>Native Scaling:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy">
|
||||||
<cstring>nativeScaling</cstring>
|
<cstring>nativeScaling</cstring>
|
||||||
|
|||||||
@ -22,9 +22,6 @@
|
|||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="title">
|
<widget class="QLabel" name="title">
|
||||||
<property name="text">
|
|
||||||
<string>Bindings for Controller0/ButtonCircle</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
<property name="buddy">
|
||||||
<cstring>bindingList</cstring>
|
<cstring>bindingList</cstring>
|
||||||
</property>
|
</property>
|
||||||
|
|||||||
@ -97,15 +97,16 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* settings_dialog
|
|||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.confirmShutdown, "UI", "ConfirmShutdown", true);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.confirmShutdown, "UI", "ConfirmShutdown", true);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnFocusLoss, "UI", "PauseOnFocusLoss", false);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnFocusLoss, "UI", "PauseOnFocusLoss", false);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnControllerDisconnection, "UI", "PauseOnControllerDisconnection", false);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnControllerDisconnection, "UI", "PauseOnControllerDisconnection", false);
|
||||||
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.promptOnStateLoadSaveFailure, "UI", "PromptOnStateLoadSaveFailure", true);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.discordPresence, "EmuCore", "EnableDiscordPresence", false);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.discordPresence, "EmuCore", "EnableDiscordPresence", false);
|
||||||
|
|
||||||
#ifdef __linux__ // Mouse locking is only supported on X11
|
#ifdef __linux__ // Mouse locking is only supported on X11
|
||||||
const bool mouse_lock_supported = QGuiApplication::platformName().toLower() == "xcb";
|
const bool mouse_lock_supported = QGuiApplication::platformName().toLower() == "xcb";
|
||||||
#else
|
#else
|
||||||
const bool mouse_lock_supported = true;
|
const bool mouse_lock_supported = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(mouse_lock_supported)
|
if (mouse_lock_supported)
|
||||||
{
|
{
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.mouseLock, "EmuCore", "EnableMouseLock", false);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.mouseLock, "EmuCore", "EnableMouseLock", false);
|
||||||
connect(m_ui.mouseLock, &QCheckBox::checkStateChanged, [](Qt::CheckState state) {
|
connect(m_ui.mouseLock, &QCheckBox::checkStateChanged, [](Qt::CheckState state) {
|
||||||
@ -196,6 +197,8 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* settings_dialog
|
|||||||
"and unpauses when you switch back."));
|
"and unpauses when you switch back."));
|
||||||
dialog()->registerWidgetHelp(m_ui.pauseOnControllerDisconnection, tr("Pause On Controller Disconnection"),
|
dialog()->registerWidgetHelp(m_ui.pauseOnControllerDisconnection, tr("Pause On Controller Disconnection"),
|
||||||
tr("Unchecked"), tr("Pauses the emulator when a controller with bindings is disconnected."));
|
tr("Unchecked"), tr("Pauses the emulator when a controller with bindings is disconnected."));
|
||||||
|
dialog()->registerWidgetHelp(m_ui.promptOnStateLoadSaveFailure, tr("Pause On State Load/Save Failure"),
|
||||||
|
tr("Checked"), tr("Display a modal dialog when a save state load/save operation fails."));
|
||||||
dialog()->registerWidgetHelp(m_ui.startFullscreen, tr("Start Fullscreen"), tr("Unchecked"),
|
dialog()->registerWidgetHelp(m_ui.startFullscreen, tr("Start Fullscreen"), tr("Unchecked"),
|
||||||
tr("Automatically switches to fullscreen mode when a game is started."));
|
tr("Automatically switches to fullscreen mode when a game is started."));
|
||||||
dialog()->registerWidgetHelp(m_ui.hideMouseCursor, tr("Hide Cursor In Fullscreen"), tr("Unchecked"),
|
dialog()->registerWidgetHelp(m_ui.hideMouseCursor, tr("Hide Cursor In Fullscreen"), tr("Unchecked"),
|
||||||
@ -224,7 +227,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* settings_dialog
|
|||||||
dialog()->registerWidgetHelp(
|
dialog()->registerWidgetHelp(
|
||||||
m_ui.backgroundBrowse, tr("Game List Background"), tr("None"),
|
m_ui.backgroundBrowse, tr("Game List Background"), tr("None"),
|
||||||
tr("Enable an animated/static background on the game list (where you launch your games).<br>"
|
tr("Enable an animated/static background on the game list (where you launch your games).<br>"
|
||||||
"This background is only visible in the library and will be hidden once a game is launched. It will also be paused when it's not in focus."));
|
"This background is only visible in the library and will be hidden once a game is launched. It will also be paused when it's not in focus."));
|
||||||
dialog()->registerWidgetHelp(
|
dialog()->registerWidgetHelp(
|
||||||
m_ui.backgroundReset, tr("Disable/Reset Game List Background"), tr("None"),
|
m_ui.backgroundReset, tr("Disable/Reset Game List Background"), tr("None"),
|
||||||
tr("Disable and reset the currently applied game list background."));
|
tr("Disable and reset the currently applied game list background."));
|
||||||
@ -241,6 +244,12 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* settings_dialog
|
|||||||
|
|
||||||
InterfaceSettingsWidget::~InterfaceSettingsWidget() = default;
|
InterfaceSettingsWidget::~InterfaceSettingsWidget() = default;
|
||||||
|
|
||||||
|
void InterfaceSettingsWidget::updatePromptOnStateLoadSaveFailureCheckbox(Qt::CheckState state)
|
||||||
|
{
|
||||||
|
QSignalBlocker blocker(m_ui.promptOnStateLoadSaveFailure);
|
||||||
|
m_ui.promptOnStateLoadSaveFailure->setCheckState(state);
|
||||||
|
}
|
||||||
|
|
||||||
void InterfaceSettingsWidget::onRenderToSeparateWindowChanged()
|
void InterfaceSettingsWidget::onRenderToSeparateWindowChanged()
|
||||||
{
|
{
|
||||||
m_ui.hideMainWindow->setEnabled(m_ui.renderToSeparateWindow->isChecked());
|
m_ui.hideMainWindow->setEnabled(m_ui.renderToSeparateWindow->isChecked());
|
||||||
@ -261,12 +270,12 @@ void InterfaceSettingsWidget::populateLanguages()
|
|||||||
void InterfaceSettingsWidget::onSetGameListBackgroundTriggered()
|
void InterfaceSettingsWidget::onSetGameListBackgroundTriggered()
|
||||||
{
|
{
|
||||||
const QString path = QDir::toNativeSeparators(
|
const QString path = QDir::toNativeSeparators(
|
||||||
QFileDialog::getOpenFileName(this, tr("Select Background Image"), QString(), IMAGE_FILE_FILTER));
|
QFileDialog::getOpenFileName(this, tr("Select Background Image"), QString(), qApp->translate("InterfaceSettingsWidget", IMAGE_FILE_FILTER)));
|
||||||
|
|
||||||
if (path.isEmpty())
|
if (path.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string relative_path = Path::MakeRelative(QDir::toNativeSeparators(path).toStdString(), EmuFolders::DataRoot);
|
std::string relative_path = Path::MakeRelative(path.toStdString(), EmuFolders::DataRoot);
|
||||||
Host::SetBaseStringSettingValue("UI", "GameListBackgroundPath", relative_path.c_str());
|
Host::SetBaseStringSettingValue("UI", "GameListBackgroundPath", relative_path.c_str());
|
||||||
|
|
||||||
Host::CommitBaseSettingChanges();
|
Host::CommitBaseSettingChanges();
|
||||||
|
|||||||
@ -15,6 +15,8 @@ public:
|
|||||||
InterfaceSettingsWidget(SettingsWindow* settings_dialog, QWidget* parent);
|
InterfaceSettingsWidget(SettingsWindow* settings_dialog, QWidget* parent);
|
||||||
~InterfaceSettingsWidget();
|
~InterfaceSettingsWidget();
|
||||||
|
|
||||||
|
void updatePromptOnStateLoadSaveFailureCheckbox(Qt::CheckState state);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void themeChanged();
|
void themeChanged();
|
||||||
void languageChanged();
|
void languageChanged();
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>725</width>
|
<width>725</width>
|
||||||
<height>625</height>
|
<height>637</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
@ -78,6 +78,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QCheckBox" name="promptOnStateLoadSaveFailure">
|
||||||
|
<property name="text">
|
||||||
|
<string>Prompt On State Load/Save Failure</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -380,6 +387,7 @@
|
|||||||
<tabstop>discordPresence</tabstop>
|
<tabstop>discordPresence</tabstop>
|
||||||
<tabstop>pauseOnControllerDisconnection</tabstop>
|
<tabstop>pauseOnControllerDisconnection</tabstop>
|
||||||
<tabstop>mouseLock</tabstop>
|
<tabstop>mouseLock</tabstop>
|
||||||
|
<tabstop>promptOnStateLoadSaveFailure</tabstop>
|
||||||
<tabstop>startFullscreen</tabstop>
|
<tabstop>startFullscreen</tabstop>
|
||||||
<tabstop>doubleClickTogglesFullscreen</tabstop>
|
<tabstop>doubleClickTogglesFullscreen</tabstop>
|
||||||
<tabstop>renderToSeparateWindow</tabstop>
|
<tabstop>renderToSeparateWindow</tabstop>
|
||||||
|
|||||||
@ -261,8 +261,10 @@ void SetupWizardDialog::onDirectoryListContextMenuRequested(const QPoint& point)
|
|||||||
const int row = selection[0].row();
|
const int row = selection[0].row();
|
||||||
|
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
|
//: Part of the right-click menu for game directory entries
|
||||||
menu.addAction(tr("Remove"), [this]() { onRemoveSearchDirectoryButtonClicked(); });
|
menu.addAction(tr("Remove"), [this]() { onRemoveSearchDirectoryButtonClicked(); });
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
|
//: Part of the right-click menu for game directory entries
|
||||||
menu.addAction(tr("Open Directory..."),
|
menu.addAction(tr("Open Directory..."),
|
||||||
[this, row]() { QtUtils::OpenURL(this, QUrl::fromLocalFile(m_ui.searchDirectoryList->item(row, 0)->text())); });
|
[this, row]() { QtUtils::OpenURL(this, QUrl::fromLocalFile(m_ui.searchDirectoryList->item(row, 0)->text())); });
|
||||||
menu.exec(m_ui.searchDirectoryList->mapToGlobal(point));
|
menu.exec(m_ui.searchDirectoryList->mapToGlobal(point));
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
#include "VMManager.h"
|
#include "VMManager.h"
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <Windows.h>
|
#include "common/RedtapeWindows.h"
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#include <winnls.h>
|
#include <winnls.h>
|
||||||
#include <shobjidl.h>
|
#include <shobjidl.h>
|
||||||
@ -61,16 +61,6 @@ ShortcutCreationDialog::ShortcutCreationDialog(QWidget* parent, const QString& t
|
|||||||
connect(m_ui.bootOptionToggle, &QCheckBox::toggled, m_ui.bootOptionDropdown, &QPushButton::setEnabled);
|
connect(m_ui.bootOptionToggle, &QCheckBox::toggled, m_ui.bootOptionDropdown, &QPushButton::setEnabled);
|
||||||
connect(m_ui.fullscreenMode, &QCheckBox::toggled, m_ui.fullscreenModeDropdown, &QPushButton::setEnabled);
|
connect(m_ui.fullscreenMode, &QCheckBox::toggled, m_ui.fullscreenModeDropdown, &QPushButton::setEnabled);
|
||||||
|
|
||||||
m_ui.shortcutDesktop->setChecked(true);
|
|
||||||
m_ui.overrideBootELFPath->setEnabled(false);
|
|
||||||
m_ui.overrideBootELFButton->setEnabled(false);
|
|
||||||
m_ui.gameArgs->setEnabled(false);
|
|
||||||
m_ui.bootOptionDropdown->setEnabled(false);
|
|
||||||
m_ui.fullscreenModeDropdown->setEnabled(false);
|
|
||||||
m_ui.loadStateIndex->setEnabled(false);
|
|
||||||
m_ui.loadStateFileBrowse->setEnabled(false);
|
|
||||||
m_ui.loadStateFilePath->setEnabled(false);
|
|
||||||
|
|
||||||
m_ui.loadStateIndex->setMaximum(VMManager::NUM_SAVE_STATE_SLOTS);
|
m_ui.loadStateIndex->setMaximum(VMManager::NUM_SAVE_STATE_SLOTS);
|
||||||
|
|
||||||
if (std::getenv("container"))
|
if (std::getenv("container"))
|
||||||
@ -80,6 +70,7 @@ ShortcutCreationDialog::ShortcutCreationDialog(QWidget* parent, const QString& t
|
|||||||
m_ui.shortcutStartMenu->setEnabled(false);
|
m_ui.shortcutStartMenu->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect(m_ui.dialogButtons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
connect(m_ui.dialogButtons, &QDialogButtonBox::accepted, this, [&]() {
|
connect(m_ui.dialogButtons, &QDialogButtonBox::accepted, this, [&]() {
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
|
|
||||||
@ -111,21 +102,24 @@ ShortcutCreationDialog::ShortcutCreationDialog(QWidget* parent, const QString& t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_ui.loadStateFileToggle->isChecked() && !m_ui.loadStateFilePath->text().isEmpty())
|
||||||
|
{
|
||||||
|
args.push_back("-statefile");
|
||||||
|
args.push_back(m_ui.loadStateFilePath->text().toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
if (m_ui.fullscreenMode->isChecked())
|
if (m_ui.fullscreenMode->isChecked())
|
||||||
args.push_back(m_ui.fullscreenModeDropdown->currentIndex() ? "-nofullscreen" : "-fullscreen");
|
args.push_back(m_ui.fullscreenModeDropdown->currentIndex() ? "-nofullscreen" : "-fullscreen");
|
||||||
|
|
||||||
if (m_ui.bigPictureModeToggle->isChecked())
|
if (m_ui.bigPictureModeToggle->isChecked())
|
||||||
args.push_back("-bigpicture");
|
args.push_back("-bigpicture");
|
||||||
|
|
||||||
m_desktop = m_ui.shortcutDesktop->isChecked();
|
|
||||||
|
|
||||||
std::string custom_args = m_ui.customArgsInput->text().toStdString();
|
std::string custom_args = m_ui.customArgsInput->text().toStdString();
|
||||||
|
|
||||||
ShortcutCreationDialog::CreateShortcut(title.toStdString(), path.toStdString(), args, custom_args, m_desktop);
|
ShortcutCreationDialog::CreateShortcut(title.toStdString(), path.toStdString(), args, custom_args, m_ui.shortcutDesktop->isChecked());
|
||||||
|
|
||||||
accept();
|
accept();
|
||||||
});
|
});
|
||||||
connect(m_ui.dialogButtons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::string game_path, std::vector<std::string> passed_cli_args, std::string custom_args, bool is_desktop)
|
void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::string game_path, std::vector<std::string> passed_cli_args, std::string custom_args, bool is_desktop)
|
||||||
@ -183,7 +177,10 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s
|
|||||||
lossless &= ShortcutCreationDialog::EscapeShortcutCommandLine(&arg);
|
lossless &= ShortcutCreationDialog::EscapeShortcutCommandLine(&arg);
|
||||||
|
|
||||||
if (!lossless)
|
if (!lossless)
|
||||||
QMessageBox::warning(this, tr("Failed to create shortcut"), tr("File path contains invalid character(s). The resulting shortcut may not work."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
{
|
||||||
|
QMessageBox::warning(this, tr("Failed to create shortcut"), tr("File path contains invalid character(s)."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ShortcutCreationDialog::EscapeShortcutCommandLine(&clean_path);
|
ShortcutCreationDialog::EscapeShortcutCommandLine(&clean_path);
|
||||||
std::string combined_args = StringUtil::JoinString(passed_cli_args.begin(), passed_cli_args.end(), " ");
|
std::string combined_args = StringUtil::JoinString(passed_cli_args.begin(), passed_cli_args.end(), " ");
|
||||||
@ -203,7 +200,7 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s
|
|||||||
if (FAILED(res))
|
if (FAILED(res))
|
||||||
{
|
{
|
||||||
Console.ErrorFmt("Failed to create shortcut: CoInitialize failed ({})", str_error(res));
|
Console.ErrorFmt("Failed to create shortcut: CoInitialize failed ({})", str_error(res));
|
||||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("CoInitialize failed (%1").arg(str_error(res)), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("CoInitialize failed (%1)").arg(str_error(res)), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,9 +310,6 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_flatpak) // Flatpak
|
|
||||||
executable_path = "flatpak run net.pcsx2.PCSX2";
|
|
||||||
|
|
||||||
// Find home directory
|
// Find home directory
|
||||||
std::string link_path;
|
std::string link_path;
|
||||||
const char* home = std::getenv("HOME");
|
const char* home = std::getenv("HOME");
|
||||||
@ -340,15 +334,30 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("Home path is empty."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("Path to the Home directory is empty."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if a shortcut already exist
|
// Copy PCSX2 icon
|
||||||
if (FileSystem::FileExists(link_path.c_str()))
|
std::string icon_dest;
|
||||||
|
if (xdg_data_home)
|
||||||
|
icon_dest = fmt::format("{}/icons/hicolor/512x512/apps/", xdg_data_home);
|
||||||
|
else
|
||||||
|
icon_dest = fmt::format("{}/.local/share/icons/hicolor/512x512/apps/", home);
|
||||||
|
|
||||||
|
std::string icon_name;
|
||||||
|
if (is_flatpak) // Flatpak
|
||||||
{
|
{
|
||||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("A shortcut with the same name already exists."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
executable_path = "flatpak run net.pcsx2.PCSX2";
|
||||||
return;
|
icon_name = "net.pcsx2.PCSX2";
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
icon_name = "PCSX2";
|
||||||
|
std::string icon_path = fmt::format("{}/{}.png", icon_dest, icon_name).c_str();
|
||||||
|
if (FileSystem::EnsureDirectoryExists(icon_dest.c_str(), true))
|
||||||
|
FileSystem::CopyFilePath(Path::Combine(EmuFolders::Resources, "icons/AppIconLarge.png").c_str(), icon_path.c_str(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shortcut CmdLine Args
|
// Shortcut CmdLine Args
|
||||||
@ -357,25 +366,13 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s
|
|||||||
lossless &= ShortcutCreationDialog::EscapeShortcutCommandLine(&arg);
|
lossless &= ShortcutCreationDialog::EscapeShortcutCommandLine(&arg);
|
||||||
|
|
||||||
if (!lossless)
|
if (!lossless)
|
||||||
QMessageBox::warning(this, tr("Failed to create shortcut"), tr("File path contains invalid character(s). The resulting shortcut may not work."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
{
|
||||||
|
QMessageBox::warning(this, tr("Failed to create shortcut"), tr("File path contains invalid character(s)."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::string cmdline = StringUtil::JoinString(passed_cli_args.begin(), passed_cli_args.end(), " ");
|
std::string cmdline = StringUtil::JoinString(passed_cli_args.begin(), passed_cli_args.end(), " ");
|
||||||
|
|
||||||
if (!is_flatpak)
|
|
||||||
{
|
|
||||||
// Copy PCSX2 icon
|
|
||||||
std::string icon_dest;
|
|
||||||
if (xdg_data_home)
|
|
||||||
icon_dest = fmt::format("{}/icons/hicolor/512x512/apps/", xdg_data_home);
|
|
||||||
else
|
|
||||||
icon_dest = fmt::format("{}/.local/share/icons/hicolor/512x512/apps/", home);
|
|
||||||
|
|
||||||
std::string icon_name = "PCSX2.png";
|
|
||||||
std::string icon_path = fmt::format("{}/{}", icon_dest, icon_name).c_str();
|
|
||||||
if (FileSystem::EnsureDirectoryExists(icon_dest.c_str(), true))
|
|
||||||
FileSystem::CopyFilePath(Path::Combine(EmuFolders::Resources, "icons/AppIconLarge.png").c_str(), icon_path.c_str(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Further string sanitization
|
// Further string sanitization
|
||||||
if (!is_flatpak)
|
if (!is_flatpak)
|
||||||
ShortcutCreationDialog::EscapeShortcutCommandLine(&executable_path);
|
ShortcutCreationDialog::EscapeShortcutCommandLine(&executable_path);
|
||||||
@ -393,7 +390,7 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s
|
|||||||
"StartupWMClass=PCSX2\n"
|
"StartupWMClass=PCSX2\n"
|
||||||
"Exec=" + final_args + "\n"
|
"Exec=" + final_args + "\n"
|
||||||
"Name=" + clean_name + "\n"
|
"Name=" + clean_name + "\n"
|
||||||
"Icon=net.pcsx2.PCSX2\n"
|
"Icon=" + icon_name + "\n"
|
||||||
"Categories=Game;Emulator;\n";
|
"Categories=Game;Emulator;\n";
|
||||||
std::string_view sv(file_content);
|
std::string_view sv(file_content);
|
||||||
|
|
||||||
|
|||||||
@ -22,8 +22,9 @@ public:
|
|||||||
bool EscapeShortcutCommandLine(std::string* cmdline);
|
bool EscapeShortcutCommandLine(std::string* cmdline);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString m_title;
|
const QString m_title;
|
||||||
QString m_path;
|
const QString m_path;
|
||||||
bool m_desktop;
|
|
||||||
|
private:
|
||||||
Ui::ShortcutCreationDialog m_ui;
|
Ui::ShortcutCreationDialog m_ui;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>500</width>
|
<width>500</width>
|
||||||
<height>685</height>
|
<height>700</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="shortcutLayout">
|
<layout class="QGridLayout" name="shortcutLayout">
|
||||||
@ -59,6 +59,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="fullscreenModeDropdown">
|
<widget class="QComboBox" name="fullscreenModeDropdown">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Force Enable</string>
|
<string>Force Enable</string>
|
||||||
@ -82,10 +85,17 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="2" colspan="2">
|
<item row="3" column="2" colspan="2">
|
||||||
<widget class="QLineEdit" name="gameArgs"/>
|
<widget class="QLineEdit" name="gameArgs">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="2" colspan="2">
|
<item row="4" column="2" colspan="2">
|
||||||
<widget class="QComboBox" name="bootOptionDropdown">
|
<widget class="QComboBox" name="bootOptionDropdown">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Fast Boot</string>
|
<string>Fast Boot</string>
|
||||||
@ -107,13 +117,20 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="2" column="3">
|
<item row="2" column="3">
|
||||||
<widget class="QPushButton" name="overrideBootELFButton">
|
<widget class="QPushButton" name="overrideBootELFButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Browse...</string>
|
<string>Browse...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="2">
|
<item row="2" column="2">
|
||||||
<widget class="QLineEdit" name="overrideBootELFPath"/>
|
<widget class="QLineEdit" name="overrideBootELFPath">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="10" column="0" colspan="4">
|
<item row="10" column="0" colspan="4">
|
||||||
<widget class="QGroupBox" name="saveStateGroup">
|
<widget class="QGroupBox" name="saveStateGroup">
|
||||||
@ -123,6 +140,9 @@
|
|||||||
<layout class="QGridLayout" name="savestateGridLayout">
|
<layout class="QGridLayout" name="savestateGridLayout">
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QSpinBox" name="loadStateIndex">
|
<widget class="QSpinBox" name="loadStateIndex">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="showGroupSeparator" stdset="0">
|
<property name="showGroupSeparator" stdset="0">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
@ -132,7 +152,11 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QLineEdit" name="loadStateFilePath"/>
|
<widget class="QLineEdit" name="loadStateFilePath">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QRadioButton" name="loadStateNone">
|
<widget class="QRadioButton" name="loadStateNone">
|
||||||
@ -160,6 +184,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="2" column="2">
|
<item row="2" column="2">
|
||||||
<widget class="QPushButton" name="loadStateFileBrowse">
|
<widget class="QPushButton" name="loadStateFileBrowse">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Browse...</string>
|
<string>Browse...</string>
|
||||||
</property>
|
</property>
|
||||||
@ -194,7 +221,7 @@
|
|||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="customArgsInstruction">
|
<widget class="QLabel" name="customArgsInstruction">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>You may add additional (space-separated) <a href="https://pcsx2.net/docs/post/cli/">custom arguments</a> that are not listed above here:</string>
|
<string>You may add additional (space-separated) <a href="https://pcsx2.net/docs/advanced/cli/">custom arguments</a> that are not listed above here:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat">
|
<property name="textFormat">
|
||||||
<enum>Qt::TextFormat::RichText</enum>
|
<enum>Qt::TextFormat::RichText</enum>
|
||||||
|
|||||||
@ -82,7 +82,7 @@ void InputRecordingViewer::openFile()
|
|||||||
{
|
{
|
||||||
QFileDialog dialog(this);
|
QFileDialog dialog(this);
|
||||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||||
dialog.setWindowTitle("Select a File");
|
dialog.setWindowTitle(tr("Select a File"));
|
||||||
dialog.setNameFilter(tr("Input Recording Files (*.p2m2)"));
|
dialog.setNameFilter(tr("Input Recording Files (*.p2m2)"));
|
||||||
QStringList fileNames;
|
QStringList fileNames;
|
||||||
if (dialog.exec())
|
if (dialog.exec())
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>AchievementSettingsWidget</name>
|
<name>AchievementSettingsWidget</name>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="../Settings/AchievementSettingsWidget.cpp" line="134"/>
|
<location filename="../Settings/AchievementSettingsWidget.cpp" line="196"/>
|
||||||
<location filename="../Settings/AchievementSettingsWidget.cpp" line="141"/>
|
<location filename="../Settings/AchievementSettingsWidget.cpp" line="203"/>
|
||||||
<source>%n seconds</source>
|
<source>%n seconds</source>
|
||||||
<translation>
|
<translation>
|
||||||
<numerusform>%n second</numerusform>
|
<numerusform>%n second</numerusform>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>Achievements</name>
|
<name>Achievements</name>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="../../pcsx2/Achievements.cpp" line="1023"/>
|
<location filename="../../pcsx2/Achievements.cpp" line="1104"/>
|
||||||
<source>You have unlocked {} of %n achievements</source>
|
<source>You have unlocked {} of %n achievements</source>
|
||||||
<comment>Achievement popup</comment>
|
<comment>Achievement popup</comment>
|
||||||
<translation>
|
<translation>
|
||||||
@ -25,7 +25,7 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="../../pcsx2/Achievements.cpp" line="1026"/>
|
<location filename="../../pcsx2/Achievements.cpp" line="1107"/>
|
||||||
<source>and earned {} of %n points</source>
|
<source>and earned {} of %n points</source>
|
||||||
<comment>Achievement popup</comment>
|
<comment>Achievement popup</comment>
|
||||||
<translation>
|
<translation>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="../../pcsx2/Achievements.cpp" line="1111"/>
|
<location filename="../../pcsx2/Achievements.cpp" line="1191"/>
|
||||||
<source>%n achievements</source>
|
<source>%n achievements</source>
|
||||||
<comment>Mastery popup</comment>
|
<comment>Mastery popup</comment>
|
||||||
<translation>
|
<translation>
|
||||||
@ -43,7 +43,7 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="../../pcsx2/Achievements.cpp" line="1113"/>
|
<location filename="../../pcsx2/Achievements.cpp" line="1193"/>
|
||||||
<source>%n points</source>
|
<source>%n points</source>
|
||||||
<comment>Mastery popup</comment>
|
<comment>Mastery popup</comment>
|
||||||
<translation>
|
<translation>
|
||||||
@ -55,8 +55,8 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>GameList</name>
|
<name>GameList</name>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="../GameList/GameListModel.cpp" line="268"/>
|
<location filename="../GameList/GameListModel.cpp" line="223"/>
|
||||||
<location filename="../../pcsx2/GameList.cpp" line="1142"/>
|
<location filename="../../pcsx2/GameList.cpp" line="1248"/>
|
||||||
<source>%n hours</source>
|
<source>%n hours</source>
|
||||||
<translation>
|
<translation>
|
||||||
<numerusform>%n hour</numerusform>
|
<numerusform>%n hour</numerusform>
|
||||||
@ -64,19 +64,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="../GameList/GameListModel.cpp" line="270"/>
|
<location filename="../GameList/GameListModel.cpp" line="227"/>
|
||||||
<location filename="../../pcsx2/GameList.cpp" line="1144"/>
|
<location filename="../../pcsx2/GameList.cpp" line="1250"/>
|
||||||
<source>%n minutes</source>
|
<source>%n minutes</source>
|
||||||
<translation>
|
<translation>
|
||||||
<numerusform>%n minute</numerusform>
|
<numerusform>%n minute</numerusform>
|
||||||
<numerusform>%n minutes</numerusform>
|
<numerusform>%n minutes</numerusform>
|
||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message numerus="yes">
|
||||||
|
<location filename="../../pcsx2/GameList.cpp" line="1252"/>
|
||||||
|
<source>%n seconds</source>
|
||||||
|
<translation>
|
||||||
|
<numerusform>%n second</numerusform>
|
||||||
|
<numerusform>%n seconds</numerusform>
|
||||||
|
</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>InputBindingWidget</name>
|
<name>InputBindingWidget</name>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="../Settings/InputBindingWidget.cpp" line="73"/>
|
<location filename="../Settings/InputBindingWidget.cpp" line="77"/>
|
||||||
<source>%n bindings</source>
|
<source>%n bindings</source>
|
||||||
<translation>
|
<translation>
|
||||||
<numerusform>%n binding</numerusform>
|
<numerusform>%n binding</numerusform>
|
||||||
@ -84,10 +92,21 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MainWindow</name>
|
||||||
|
<message numerus="yes">
|
||||||
|
<location filename="../MainWindow.cpp" line="3061"/>
|
||||||
|
<source>%n save states deleted.</source>
|
||||||
|
<translation>
|
||||||
|
<numerusform>%n save state deleted.</numerusform>
|
||||||
|
<numerusform>%n save states deleted.</numerusform>
|
||||||
|
</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Patch</name>
|
<name>Patch</name>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="../../pcsx2/Patch.cpp" line="698"/>
|
<location filename="../../pcsx2/Patch.cpp" line="768"/>
|
||||||
<source>%n GameDB patches are active.</source>
|
<source>%n GameDB patches are active.</source>
|
||||||
<comment>OSD Message</comment>
|
<comment>OSD Message</comment>
|
||||||
<translation>
|
<translation>
|
||||||
@ -96,7 +115,7 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="../../pcsx2/Patch.cpp" line="705"/>
|
<location filename="../../pcsx2/Patch.cpp" line="775"/>
|
||||||
<source>%n game patches are active.</source>
|
<source>%n game patches are active.</source>
|
||||||
<comment>OSD Message</comment>
|
<comment>OSD Message</comment>
|
||||||
<translation>
|
<translation>
|
||||||
@ -105,7 +124,7 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="../../pcsx2/Patch.cpp" line="712"/>
|
<location filename="../../pcsx2/Patch.cpp" line="781"/>
|
||||||
<source>%n cheat patches are active.</source>
|
<source>%n cheat patches are active.</source>
|
||||||
<comment>OSD Message</comment>
|
<comment>OSD Message</comment>
|
||||||
<translation>
|
<translation>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -2942,8 +2942,19 @@ static void cdvdWrite16(u8 rt) // SCOMMAND
|
|||||||
|
|
||||||
bit_ofs = mg_BIToffset(&cdvd.mg_buffer[0]);
|
bit_ofs = mg_BIToffset(&cdvd.mg_buffer[0]);
|
||||||
|
|
||||||
memcpy(&cdvd.mg_kbit[0], &cdvd.mg_buffer[bit_ofs - 0x20], 0x10);
|
const size_t buf_size = sizeof(cdvd.mg_buffer);
|
||||||
memcpy(&cdvd.mg_kcon[0], &cdvd.mg_buffer[bit_ofs - 0x10], 0x10);
|
|
||||||
|
if (bit_ofs < 0x20 || (size_t)bit_ofs > buf_size)
|
||||||
|
{
|
||||||
|
fail_pol_cal();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t kbit_ofs = bit_ofs - 0x20;
|
||||||
|
const size_t kcon_ofs = bit_ofs - 0x10;
|
||||||
|
|
||||||
|
std::memcpy(&cdvd.mg_kbit[0], &cdvd.mg_buffer[kbit_ofs], 0x10);
|
||||||
|
std::memcpy(&cdvd.mg_kcon[0], &cdvd.mg_buffer[kcon_ofs], 0x10);
|
||||||
|
|
||||||
if ((cdvd.mg_buffer[bit_ofs + 5] || cdvd.mg_buffer[bit_ofs + 6] || cdvd.mg_buffer[bit_ofs + 7]) ||
|
if ((cdvd.mg_buffer[bit_ofs + 5] || cdvd.mg_buffer[bit_ofs + 6] || cdvd.mg_buffer[bit_ofs + 7]) ||
|
||||||
(GetBufferU16(&cdvd.mg_buffer[0],bit_ofs + 4) * 16 + bit_ofs + 8 + 16 != GetBufferU16(&cdvd.mg_buffer[0], 0x14)))
|
(GetBufferU16(&cdvd.mg_buffer[0],bit_ofs + 4) * 16 + bit_ofs + 8 + 16 != GetBufferU16(&cdvd.mg_buffer[0], 0x14)))
|
||||||
@ -2969,7 +2980,31 @@ static void cdvdWrite16(u8 rt) // SCOMMAND
|
|||||||
{
|
{
|
||||||
SetSCMDResultSize(3); //in:0
|
SetSCMDResultSize(3); //in:0
|
||||||
const int bit_ofs = mg_BIToffset(&cdvd.mg_buffer[0]);
|
const int bit_ofs = mg_BIToffset(&cdvd.mg_buffer[0]);
|
||||||
memcpy(&cdvd.mg_buffer[0], &cdvd.mg_buffer[bit_ofs], static_cast<size_t>(8 + 16 * static_cast<int>(cdvd.mg_buffer[bit_ofs + 4])));
|
|
||||||
|
if (bit_ofs < 0)
|
||||||
|
{
|
||||||
|
fail_pol_cal();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t bufsize = sizeof(cdvd.mg_buffer);
|
||||||
|
const size_t ofs = static_cast<size_t>(bit_ofs);
|
||||||
|
|
||||||
|
if (ofs > bufsize - 5) // Make sure we can read the block count
|
||||||
|
{
|
||||||
|
fail_pol_cal();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const unsigned int blocks = static_cast<unsigned int>(cdvd.mg_buffer[ofs + 4]);
|
||||||
|
const size_t copy_len = 8 + 16 * static_cast<size_t>(blocks);
|
||||||
|
|
||||||
|
if (copy_len > bufsize - ofs) // Make sure we can read the blocks
|
||||||
|
{
|
||||||
|
fail_pol_cal();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memmove(&cdvd.mg_buffer[0], &cdvd.mg_buffer[ofs], copy_len);
|
||||||
|
|
||||||
cdvd.mg_maxsize = 0; // don't allow any write
|
cdvd.mg_maxsize = 0; // don't allow any write
|
||||||
cdvd.mg_size = 8 + 16 * cdvd.mg_buffer[4]; //new offset, i just moved the data
|
cdvd.mg_size = 8 + 16 * cdvd.mg_buffer[4]; //new offset, i just moved the data
|
||||||
|
|||||||
@ -513,7 +513,7 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
|||||||
if (m_feature_level < D3D_FEATURE_LEVEL_11_0)
|
if (m_feature_level < D3D_FEATURE_LEVEL_11_0)
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage("d3d11_feature_level_warning", ICON_FA_TRIANGLE_EXCLAMATION,
|
Host::AddIconOSDMessage("d3d11_feature_level_warning", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||||
TRANSLATE_SV("GS", "The Direct3D11 renderer is running at feature level 10.0. This is an UNSUPPORTED configuration.\n"
|
TRANSLATE_SV("GS", "The Direct3D 11 renderer is running at feature level 10.0. This is an UNSUPPORTED configuration.\n"
|
||||||
"Do not request support, please upgrade your hardware/drivers first."),
|
"Do not request support, please upgrade your hardware/drivers first."),
|
||||||
Host::OSD_WARNING_DURATION);
|
Host::OSD_WARNING_DURATION);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3427,6 +3427,9 @@ void GSDevice12::BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_b
|
|||||||
m_dirty_flags &= ~DIRTY_FLAG_RENDER_TARGET;
|
m_dirty_flags &= ~DIRTY_FLAG_RENDER_TARGET;
|
||||||
m_in_render_pass = true;
|
m_in_render_pass = true;
|
||||||
|
|
||||||
|
if (stencil_end == D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD)
|
||||||
|
GL_INS("D3D12: BeginRenderPass() end stencil is DISCARDED.");
|
||||||
|
|
||||||
D3D12_RENDER_PASS_RENDER_TARGET_DESC rt = {};
|
D3D12_RENDER_PASS_RENDER_TARGET_DESC rt = {};
|
||||||
if (m_current_render_target)
|
if (m_current_render_target)
|
||||||
{
|
{
|
||||||
@ -4008,7 +4011,8 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
|||||||
draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||||
stencil_DATE ? D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE :
|
stencil_DATE ? D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE :
|
||||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
|
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
|
||||||
stencil_DATE ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD :
|
stencil_DATE ? (draw_rt_clone ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE :
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD) :
|
||||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||||
clear_color, draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1);
|
clear_color, draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,14 +106,15 @@ static void HotkeyLoadStateSlot(s32 slot)
|
|||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
if (!VMManager::LoadStateFromSlot(slot, false, &error))
|
if (!VMManager::LoadStateFromSlot(slot, false, &error))
|
||||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
FullscreenUI::ReportStateLoadError(error.GetDescription(), slot, false);
|
||||||
error.GetDescription(), Host::OSD_INFO_DURATION);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HotkeySaveStateSlot(s32 slot)
|
static void HotkeySaveStateSlot(s32 slot)
|
||||||
{
|
{
|
||||||
VMManager::SaveStateToSlot(slot);
|
VMManager::SaveStateToSlot(slot, true, [slot](const std::string& error) {
|
||||||
|
FullscreenUI::ReportStateSaveError(error, slot);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CanPause()
|
static bool CanPause()
|
||||||
|
|||||||
@ -630,9 +630,9 @@ namespace FullscreenUI
|
|||||||
static std::unique_ptr<GameList::Entry> s_game_settings_entry;
|
static std::unique_ptr<GameList::Entry> s_game_settings_entry;
|
||||||
static std::vector<std::pair<std::string, bool>> s_game_list_directories_cache;
|
static std::vector<std::pair<std::string, bool>> s_game_list_directories_cache;
|
||||||
static std::vector<GSAdapterInfo> s_graphics_adapter_list_cache;
|
static std::vector<GSAdapterInfo> s_graphics_adapter_list_cache;
|
||||||
static Patch::PatchInfoList s_game_patch_list;
|
static std::vector<Patch::PatchInfo> s_game_patch_list;
|
||||||
static std::vector<std::string> s_enabled_game_patch_cache;
|
static std::vector<std::string> s_enabled_game_patch_cache;
|
||||||
static Patch::PatchInfoList s_game_cheats_list;
|
static std::vector<Patch::PatchInfo> s_game_cheats_list;
|
||||||
static std::vector<std::string> s_enabled_game_cheat_cache;
|
static std::vector<std::string> s_enabled_game_cheat_cache;
|
||||||
static u32 s_game_cheat_unlabelled_count = 0;
|
static u32 s_game_cheat_unlabelled_count = 0;
|
||||||
static std::vector<const HotkeyInfo*> s_hotkey_list_cache;
|
static std::vector<const HotkeyInfo*> s_hotkey_list_cache;
|
||||||
@ -670,7 +670,8 @@ namespace FullscreenUI
|
|||||||
static void DrawSaveStateSelector(bool is_loading);
|
static void DrawSaveStateSelector(bool is_loading);
|
||||||
static bool OpenLoadStateSelectorForGameResume(const GameList::Entry* entry);
|
static bool OpenLoadStateSelectorForGameResume(const GameList::Entry* entry);
|
||||||
static void DrawResumeStateSelector();
|
static void DrawResumeStateSelector();
|
||||||
static void DoLoadState(std::string path);
|
static void DoLoadState(std::string path, std::optional<s32> slot, bool backup);
|
||||||
|
static void DoSaveState(s32 slot);
|
||||||
|
|
||||||
static std::vector<SaveStateListEntry> s_save_state_selector_slots;
|
static std::vector<SaveStateListEntry> s_save_state_selector_slots;
|
||||||
static std::string s_save_state_selector_game_path;
|
static std::string s_save_state_selector_game_path;
|
||||||
@ -1202,11 +1203,11 @@ void FullscreenUI::Shutdown(bool clear_state)
|
|||||||
s_about_window_open = false;
|
s_about_window_open = false;
|
||||||
}
|
}
|
||||||
s_hotkey_list_cache = {};
|
s_hotkey_list_cache = {};
|
||||||
|
|
||||||
s_custom_background_texture.reset();
|
s_custom_background_texture.reset();
|
||||||
s_custom_background_path.clear();
|
s_custom_background_path.clear();
|
||||||
s_custom_background_enabled = false;
|
s_custom_background_enabled = false;
|
||||||
|
|
||||||
DestroyResources();
|
DestroyResources();
|
||||||
ImGuiFullscreen::Shutdown(clear_state);
|
ImGuiFullscreen::Shutdown(clear_state);
|
||||||
s_initialized = false;
|
s_initialized = false;
|
||||||
@ -1220,7 +1221,7 @@ void FullscreenUI::Render()
|
|||||||
|
|
||||||
// see if background setting changed
|
// see if background setting changed
|
||||||
static std::string s_last_background_path;
|
static std::string s_last_background_path;
|
||||||
std::string current_path = Host::GetBaseStringSettingValue("UI", "GameListBackgroundPath");
|
std::string current_path = Host::GetBaseStringSettingValue("UI", "FSUIBackgroundPath");
|
||||||
if (s_last_background_path != current_path)
|
if (s_last_background_path != current_path)
|
||||||
{
|
{
|
||||||
s_last_background_path = current_path;
|
s_last_background_path = current_path;
|
||||||
@ -1239,8 +1240,9 @@ void FullscreenUI::Render()
|
|||||||
s_current_main_window == MainWindowType::Exit ||
|
s_current_main_window == MainWindowType::Exit ||
|
||||||
s_current_main_window == MainWindowType::GameList ||
|
s_current_main_window == MainWindowType::GameList ||
|
||||||
s_current_main_window == MainWindowType::GameListSettings ||
|
s_current_main_window == MainWindowType::GameListSettings ||
|
||||||
s_current_main_window == MainWindowType::Settings) && s_custom_background_enabled && s_custom_background_texture;
|
s_current_main_window == MainWindowType::Settings) &&
|
||||||
|
!VMManager::HasValidVM() && s_custom_background_enabled && s_custom_background_texture;
|
||||||
|
|
||||||
ImVec4 original_background_color;
|
ImVec4 original_background_color;
|
||||||
if (should_draw_background)
|
if (should_draw_background)
|
||||||
{
|
{
|
||||||
@ -1690,8 +1692,8 @@ bool FullscreenUI::ShouldDefaultToGameList()
|
|||||||
|
|
||||||
void FullscreenUI::LoadCustomBackground()
|
void FullscreenUI::LoadCustomBackground()
|
||||||
{
|
{
|
||||||
std::string path = Host::GetBaseStringSettingValue("UI", "GameListBackgroundPath");
|
std::string path = Host::GetBaseStringSettingValue("UI", "FSUIBackgroundPath");
|
||||||
|
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
{
|
{
|
||||||
s_custom_background_texture.reset();
|
s_custom_background_texture.reset();
|
||||||
@ -1757,27 +1759,33 @@ void FullscreenUI::DrawCustomBackground()
|
|||||||
|
|
||||||
const ImGuiIO& io = ImGui::GetIO();
|
const ImGuiIO& io = ImGui::GetIO();
|
||||||
const ImVec2 display_size = io.DisplaySize;
|
const ImVec2 display_size = io.DisplaySize;
|
||||||
|
|
||||||
const float opacity = Host::GetBaseFloatSettingValue("UI", "GameListBackgroundOpacity", 100.0f) / 100.0f;
|
const u8 alpha = static_cast<u8>(Host::GetBaseFloatSettingValue("UI", "FSUIBackgroundOpacity", 100.0f) * 2.55f);
|
||||||
const std::string mode = Host::GetBaseStringSettingValue("UI", "GameListBackgroundMode", "fit");
|
const std::string mode = Host::GetBaseStringSettingValue("UI", "FSUIBackgroundMode", "fit");
|
||||||
|
|
||||||
const float tex_width = static_cast<float>(s_custom_background_texture->GetWidth());
|
const float tex_width = static_cast<float>(s_custom_background_texture->GetWidth());
|
||||||
const float tex_height = static_cast<float>(s_custom_background_texture->GetHeight());
|
const float tex_height = static_cast<float>(s_custom_background_texture->GetHeight());
|
||||||
|
|
||||||
ImVec2 img_min, img_max;
|
// Override the UIBackgroundColor that windows use
|
||||||
|
// We need to make windows transparent so our background image shows through
|
||||||
|
const ImVec4 transparent_bg = ImVec4(UIBackgroundColor.x, UIBackgroundColor.y, UIBackgroundColor.z, 0.0f);
|
||||||
|
ImGuiFullscreen::UIBackgroundColor = transparent_bg;
|
||||||
|
|
||||||
|
ImDrawList* bg_draw_list = ImGui::GetBackgroundDrawList();
|
||||||
|
const ImU32 col = IM_COL32(255, 255, 255, alpha);
|
||||||
|
const ImTextureID tex_id = reinterpret_cast<ImTextureID>(s_custom_background_texture->GetNativeHandle());
|
||||||
|
|
||||||
if (mode == "stretch")
|
if (mode == "stretch")
|
||||||
{
|
{
|
||||||
// stretch to fill entire display (ignores aspect ratio)
|
// stretch to fill entire display (ignores aspect ratio)
|
||||||
img_min = ImVec2(0.0f, 0.0f);
|
bg_draw_list->AddImage(tex_id, ImVec2(0.0f, 0.0f), display_size, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), col);
|
||||||
img_max = display_size;
|
|
||||||
}
|
}
|
||||||
else if (mode == "fill")
|
else if (mode == "fill")
|
||||||
{
|
{
|
||||||
// Fill display while preserving aspect ratio (could crop edges)
|
// Fill display while preserving aspect ratio (could crop edges)
|
||||||
const float display_aspect = display_size.x / display_size.y;
|
const float display_aspect = display_size.x / display_size.y;
|
||||||
const float tex_aspect = tex_width / tex_height;
|
const float tex_aspect = tex_width / tex_height;
|
||||||
|
|
||||||
float scale;
|
float scale;
|
||||||
if (tex_aspect > display_aspect)
|
if (tex_aspect > display_aspect)
|
||||||
{
|
{
|
||||||
@ -1789,21 +1797,77 @@ void FullscreenUI::DrawCustomBackground()
|
|||||||
// Image is taller scale to width and crop top/bottom
|
// Image is taller scale to width and crop top/bottom
|
||||||
scale = display_size.x / tex_width;
|
scale = display_size.x / tex_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float scaled_width = tex_width * scale;
|
const float scaled_width = tex_width * scale;
|
||||||
const float scaled_height = tex_height * scale;
|
const float scaled_height = tex_height * scale;
|
||||||
const float offset_x = (display_size.x - scaled_width) * 0.5f;
|
const float offset_x = (display_size.x - scaled_width) * 0.5f;
|
||||||
const float offset_y = (display_size.y - scaled_height) * 0.5f;
|
const float offset_y = (display_size.y - scaled_height) * 0.5f;
|
||||||
|
|
||||||
img_min = ImVec2(offset_x, offset_y);
|
bg_draw_list->AddImage(tex_id,
|
||||||
img_max = ImVec2(offset_x + scaled_width, offset_y + scaled_height);
|
ImVec2(offset_x, offset_y),
|
||||||
|
ImVec2(offset_x + scaled_width, offset_y + scaled_height),
|
||||||
|
ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), col);
|
||||||
|
}
|
||||||
|
else if (mode == "center")
|
||||||
|
{
|
||||||
|
// Center image at original size
|
||||||
|
const float offset_x = (display_size.x - tex_width) * 0.5f;
|
||||||
|
const float offset_y = (display_size.y - tex_height) * 0.5f;
|
||||||
|
|
||||||
|
bg_draw_list->AddImage(tex_id,
|
||||||
|
ImVec2(offset_x, offset_y),
|
||||||
|
ImVec2(offset_x + tex_width, offset_y + tex_height),
|
||||||
|
ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), col);
|
||||||
|
}
|
||||||
|
else if (mode == "tile")
|
||||||
|
{
|
||||||
|
// Tile image across entire display
|
||||||
|
// If the image is extremely small, this approach can generate millions of quads
|
||||||
|
// and overflow the backend stream buffer (e.g. Vulkan assertion in VKStreamBuffer).
|
||||||
|
// Since we cannot switch ImGui's sampler to wrap (yet), clamp the maximum number of quads
|
||||||
|
constexpr int MAX_TILE_QUADS = 16384;
|
||||||
|
|
||||||
|
float tile_width = tex_width;
|
||||||
|
float tile_height = tex_height;
|
||||||
|
int tiles_x = static_cast<int>(std::ceil(display_size.x / tile_width));
|
||||||
|
int tiles_y = static_cast<int>(std::ceil(display_size.y / tile_height));
|
||||||
|
|
||||||
|
const int total_tiles = tiles_x * tiles_y;
|
||||||
|
if (total_tiles > MAX_TILE_QUADS)
|
||||||
|
{
|
||||||
|
const float scale = std::sqrt(static_cast<float>(total_tiles) / static_cast<float>(MAX_TILE_QUADS));
|
||||||
|
tile_width *= scale;
|
||||||
|
tile_height *= scale;
|
||||||
|
tiles_x = static_cast<int>(std::ceil(display_size.x / tile_width));
|
||||||
|
tiles_y = static_cast<int>(std::ceil(display_size.y / tile_height));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0; y < tiles_y; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < tiles_x; x++)
|
||||||
|
{
|
||||||
|
const float tile_x = static_cast<float>(x) * tile_width;
|
||||||
|
const float tile_y = static_cast<float>(y) * tile_height;
|
||||||
|
const float tile_max_x = std::min(tile_x + tile_width, display_size.x);
|
||||||
|
const float tile_max_y = std::min(tile_y + tile_height, display_size.y);
|
||||||
|
|
||||||
|
// get uvs for partial tiles at edges
|
||||||
|
const float uv_max_x = (tile_max_x - tile_x) / tile_width;
|
||||||
|
const float uv_max_y = (tile_max_y - tile_y) / tile_height;
|
||||||
|
|
||||||
|
bg_draw_list->AddImage(tex_id,
|
||||||
|
ImVec2(tile_x, tile_y),
|
||||||
|
ImVec2(tile_max_x, tile_max_y),
|
||||||
|
ImVec2(0.0f, 0.0f), ImVec2(uv_max_x, uv_max_y), col);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else // "fit" or default
|
else // "fit" or default
|
||||||
{
|
{
|
||||||
// Fit on screen while preserving aspect ratio (no cropping)
|
// Fit on screen while preserving aspect ratio (no cropping)
|
||||||
const float display_aspect = display_size.x / display_size.y;
|
const float display_aspect = display_size.x / display_size.y;
|
||||||
const float tex_aspect = tex_width / tex_height;
|
const float tex_aspect = tex_width / tex_height;
|
||||||
|
|
||||||
float scale;
|
float scale;
|
||||||
if (tex_aspect > display_aspect)
|
if (tex_aspect > display_aspect)
|
||||||
{
|
{
|
||||||
@ -1815,25 +1879,17 @@ void FullscreenUI::DrawCustomBackground()
|
|||||||
// Image is taller than display
|
// Image is taller than display
|
||||||
scale = display_size.y / tex_height;
|
scale = display_size.y / tex_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float scaled_width = tex_width * scale;
|
const float scaled_width = tex_width * scale;
|
||||||
const float scaled_height = tex_height * scale;
|
const float scaled_height = tex_height * scale;
|
||||||
const float offset_x = (display_size.x - scaled_width) * 0.5f;
|
const float offset_x = (display_size.x - scaled_width) * 0.5f;
|
||||||
const float offset_y = (display_size.y - scaled_height) * 0.5f;
|
const float offset_y = (display_size.y - scaled_height) * 0.5f;
|
||||||
|
|
||||||
img_min = ImVec2(offset_x, offset_y);
|
|
||||||
img_max = ImVec2(offset_x + scaled_width, offset_y + scaled_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override the UIBackgroundColor that windows use
|
bg_draw_list->AddImage(tex_id,
|
||||||
// We need to make windows transparent so our background image shows through
|
ImVec2(offset_x, offset_y),
|
||||||
const ImVec4 transparent_bg = ImVec4(UIBackgroundColor.x, UIBackgroundColor.y, UIBackgroundColor.z, 0.0f);
|
ImVec2(offset_x + scaled_width, offset_y + scaled_height),
|
||||||
ImGuiFullscreen::UIBackgroundColor = transparent_bg;
|
ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), col);
|
||||||
|
}
|
||||||
ImDrawList* bg_draw_list = ImGui::GetBackgroundDrawList();
|
|
||||||
const ImU32 col = IM_COL32(255, 255, 255, static_cast<u8>(opacity * 255.0f));
|
|
||||||
bg_draw_list->AddImage(reinterpret_cast<ImTextureID>(s_custom_background_texture->GetNativeHandle()),
|
|
||||||
img_min, img_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), col);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@ -3358,7 +3414,7 @@ void FullscreenUI::DrawIPAddressSetting(SettingsInterface* bsi, const char* titl
|
|||||||
|
|
||||||
char ip_str[16];
|
char ip_str[16];
|
||||||
std::snprintf(ip_str, sizeof(ip_str), "%d.%d.%d.%d", ip_octets[0], ip_octets[1], ip_octets[2], ip_octets[3]);
|
std::snprintf(ip_str, sizeof(ip_str), "%d.%d.%d.%d", ip_octets[0], ip_octets[1], ip_octets[2], ip_octets[3]);
|
||||||
|
|
||||||
const char* message;
|
const char* message;
|
||||||
switch (ip_type)
|
switch (ip_type)
|
||||||
{
|
{
|
||||||
@ -3382,9 +3438,9 @@ void FullscreenUI::DrawIPAddressSetting(SettingsInterface* bsi, const char* titl
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGuiFullscreen::CloseInputDialog();
|
ImGuiFullscreen::CloseInputDialog();
|
||||||
|
|
||||||
std::string ip_str_value(ip_str);
|
std::string ip_str_value(ip_str);
|
||||||
|
|
||||||
ImGuiFullscreen::OpenInputStringDialog(
|
ImGuiFullscreen::OpenInputStringDialog(
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
@ -3401,10 +3457,10 @@ void FullscreenUI::DrawIPAddressSetting(SettingsInterface* bsi, const char* titl
|
|||||||
new_octets[i] = std::clamp(std::atoi(segment.c_str()), 0, 255);
|
new_octets[i] = std::clamp(std::atoi(segment.c_str()), 0, 255);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
char ip_str[16];
|
char ip_str[16];
|
||||||
std::snprintf(ip_str, sizeof(ip_str), "%d.%d.%d.%d", new_octets[0], new_octets[1], new_octets[2], new_octets[3]);
|
std::snprintf(ip_str, sizeof(ip_str), "%d.%d.%d.%d", new_octets[0], new_octets[1], new_octets[2], new_octets[3]);
|
||||||
|
|
||||||
if (IsEditingGameSettings(bsi) && strcmp(ip_str, default_value) == 0)
|
if (IsEditingGameSettings(bsi) && strcmp(ip_str, default_value) == 0)
|
||||||
bsi->DeleteValue(section, key);
|
bsi->DeleteValue(section, key);
|
||||||
else
|
else
|
||||||
@ -3581,7 +3637,7 @@ void FullscreenUI::PopulateGameListDirectoryCache(SettingsInterface* si)
|
|||||||
|
|
||||||
void FullscreenUI::PopulatePatchesAndCheatsList(const std::string_view serial, u32 crc)
|
void FullscreenUI::PopulatePatchesAndCheatsList(const std::string_view serial, u32 crc)
|
||||||
{
|
{
|
||||||
constexpr auto sort_patches = [](Patch::PatchInfoList& list) {
|
constexpr auto sort_patches = [](std::vector<Patch::PatchInfo>& list) {
|
||||||
std::sort(list.begin(), list.end(), [](const Patch::PatchInfo& lhs, const Patch::PatchInfo& rhs) { return lhs.name < rhs.name; });
|
std::sort(list.begin(), list.end(), [](const Patch::PatchInfo& lhs, const Patch::PatchInfo& rhs) { return lhs.name < rhs.name; });
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3629,7 +3685,7 @@ void FullscreenUI::DrawSettingsWindow()
|
|||||||
ImVec2(io.DisplaySize.x, LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) +
|
ImVec2(io.DisplaySize.x, LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) +
|
||||||
(LayoutScale(LAYOUT_MENU_BUTTON_Y_PADDING) * 2.0f) + LayoutScale(2.0f));
|
(LayoutScale(LAYOUT_MENU_BUTTON_Y_PADDING) * 2.0f) + LayoutScale(2.0f));
|
||||||
|
|
||||||
const bool using_custom_bg = s_custom_background_enabled && s_custom_background_texture;
|
const bool using_custom_bg = !VMManager::HasValidVM() && s_custom_background_enabled && s_custom_background_texture;
|
||||||
const float header_bg_alpha = VMManager::HasValidVM() ? 0.90f : 1.0f;
|
const float header_bg_alpha = VMManager::HasValidVM() ? 0.90f : 1.0f;
|
||||||
const float content_bg_alpha = using_custom_bg ? 0.0f : (VMManager::HasValidVM() ? 0.90f : 1.0f);
|
const float content_bg_alpha = using_custom_bg ? 0.0f : (VMManager::HasValidVM() ? 0.90f : 1.0f);
|
||||||
SettingsInterface* bsi = GetEditingSettingsInterface();
|
SettingsInterface* bsi = GetEditingSettingsInterface();
|
||||||
@ -4051,22 +4107,20 @@ void FullscreenUI::DrawInterfaceSettingsPage()
|
|||||||
"EmuCore", "UseSavestateSelector", true);
|
"EmuCore", "UseSavestateSelector", true);
|
||||||
|
|
||||||
MenuHeading(FSUI_CSTR("Background"));
|
MenuHeading(FSUI_CSTR("Background"));
|
||||||
|
|
||||||
std::string background_path = bsi->GetStringValue("UI", "GameListBackgroundPath", "");
|
std::string background_path = bsi->GetStringValue("UI", "FSUIBackgroundPath", "");
|
||||||
const bool background_enabled = bsi->GetBoolValue("UI", "GameListBackgroundEnabled", false);
|
|
||||||
|
|
||||||
std::string background_display = FSUI_STR("None");
|
std::string background_display = FSUI_STR("None");
|
||||||
if (!background_path.empty() && background_enabled)
|
if (!background_path.empty())
|
||||||
{
|
{
|
||||||
background_display = Path::GetFileName(background_path);
|
background_display = Path::GetFileName(background_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_IMAGE, "Background Image"),
|
if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_IMAGE, "Background Image"),
|
||||||
FSUI_CSTR("Select a custom background image to use in Big Picture Mode menus."),
|
FSUI_CSTR("Select a custom background image to use in Big Picture Mode menus.\n\nSupported formats: PNG, JPG, JPEG, BMP."),
|
||||||
background_display.c_str()))
|
background_display.c_str()))
|
||||||
{
|
{
|
||||||
OpenFileSelector(FSUI_ICONSTR(ICON_FA_IMAGE, "Select Background Image"), false,
|
OpenFileSelector(FSUI_ICONSTR(ICON_FA_IMAGE, "Select Background Image"), false, [](const std::string& path) {
|
||||||
[](const std::string& path) {
|
|
||||||
if (!path.empty())
|
if (!path.empty())
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@ -4074,47 +4128,48 @@ void FullscreenUI::DrawInterfaceSettingsPage()
|
|||||||
SettingsInterface* bsi = GetEditingSettingsInterface(false);
|
SettingsInterface* bsi = GetEditingSettingsInterface(false);
|
||||||
|
|
||||||
std::string relative_path = Path::MakeRelative(path, EmuFolders::DataRoot);
|
std::string relative_path = Path::MakeRelative(path, EmuFolders::DataRoot);
|
||||||
bsi->SetStringValue("UI", "GameListBackgroundPath", relative_path.c_str());
|
bsi->SetStringValue("UI", "FSUIBackgroundPath", relative_path.c_str());
|
||||||
bsi->SetBoolValue("UI", "GameListBackgroundEnabled", true);
|
bsi->SetBoolValue("UI", "FSUIBackgroundEnabled", true);
|
||||||
SetSettingsChanged(bsi);
|
SetSettingsChanged(bsi);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadCustomBackground();
|
LoadCustomBackground();
|
||||||
}
|
}
|
||||||
CloseFileSelector();
|
CloseFileSelector(); }, GetImageFileFilters());
|
||||||
},
|
|
||||||
GetImageFileFilters());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MenuButton(FSUI_ICONSTR(ICON_FA_XMARK, "Clear Background Image"),
|
if (MenuButton(FSUI_ICONSTR(ICON_FA_XMARK, "Clear Background Image"),
|
||||||
FSUI_CSTR("Removes the custom background image.")))
|
FSUI_CSTR("Removes the custom background image.")))
|
||||||
{
|
{
|
||||||
bsi->DeleteValue("UI", "GameListBackgroundPath");
|
bsi->DeleteValue("UI", "FSUIBackgroundPath");
|
||||||
bsi->SetBoolValue("UI", "GameListBackgroundEnabled", false);
|
|
||||||
SetSettingsChanged(bsi);
|
SetSettingsChanged(bsi);
|
||||||
|
|
||||||
s_custom_background_texture.reset();
|
s_custom_background_texture.reset();
|
||||||
s_custom_background_path.clear();
|
s_custom_background_path.clear();
|
||||||
s_custom_background_enabled = false;
|
s_custom_background_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_DROPLET, "Background Opacity"),
|
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_DROPLET, "Background Opacity"),
|
||||||
FSUI_CSTR("Sets the transparency of the custom background image."),
|
FSUI_CSTR("Sets the transparency of the custom background image."),
|
||||||
"UI", "GameListBackgroundOpacity", 100, 0, 100, "%d%%");
|
"UI", "FSUIBackgroundOpacity", 100, 0, 100, "%d%%");
|
||||||
|
|
||||||
static constexpr const char* s_background_mode_names[] = {
|
static constexpr const char* s_background_mode_names[] = {
|
||||||
FSUI_NSTR("Fit"),
|
FSUI_NSTR("Fit"),
|
||||||
FSUI_NSTR("Fill"),
|
FSUI_NSTR("Fill"),
|
||||||
FSUI_NSTR("Stretch"),
|
FSUI_NSTR("Stretch"),
|
||||||
|
FSUI_NSTR("Center"),
|
||||||
|
FSUI_NSTR("Tile"),
|
||||||
};
|
};
|
||||||
static constexpr const char* s_background_mode_values[] = {
|
static constexpr const char* s_background_mode_values[] = {
|
||||||
"fit",
|
"fit",
|
||||||
"fill",
|
"fill",
|
||||||
"stretch",
|
"stretch",
|
||||||
|
"center",
|
||||||
|
"tile",
|
||||||
};
|
};
|
||||||
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_EXPAND, "Background Mode"),
|
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_EXPAND, "Background Mode"),
|
||||||
FSUI_CSTR("Select how to display the background image."),
|
FSUI_CSTR("Select how to display the background image."),
|
||||||
"UI", "GameListBackgroundMode", "fit", s_background_mode_names, s_background_mode_values, std::size(s_background_mode_names), true);
|
"UI", "FSUIBackgroundMode", "fit", s_background_mode_names, s_background_mode_values, std::size(s_background_mode_names), true);
|
||||||
|
|
||||||
MenuHeading(FSUI_CSTR("Behaviour"));
|
MenuHeading(FSUI_CSTR("Behaviour"));
|
||||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_SNOOZE, "Inhibit Screensaver"),
|
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_SNOOZE, "Inhibit Screensaver"),
|
||||||
@ -4129,6 +4184,8 @@ void FullscreenUI::DrawInterfaceSettingsPage()
|
|||||||
FSUI_CSTR("Pauses the emulator when a controller with bindings is disconnected."), "UI", "PauseOnControllerDisconnection", false);
|
FSUI_CSTR("Pauses the emulator when a controller with bindings is disconnected."), "UI", "PauseOnControllerDisconnection", false);
|
||||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_RECTANGLE_LIST, "Pause On Menu"),
|
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_RECTANGLE_LIST, "Pause On Menu"),
|
||||||
FSUI_CSTR("Pauses the emulator when you open the quick menu, and unpauses when you close it."), "UI", "PauseOnMenu", true);
|
FSUI_CSTR("Pauses the emulator when you open the quick menu, and unpauses when you close it."), "UI", "PauseOnMenu", true);
|
||||||
|
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_FLOPPY_DISK, "Prompt On State Load/Save Failure"),
|
||||||
|
FSUI_CSTR("Display a modal dialog when a save state load/save operation fails."), "UI", "PromptOnStateLoadSaveFailure", true);
|
||||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_POWER_OFF, "Confirm Shutdown"),
|
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_POWER_OFF, "Confirm Shutdown"),
|
||||||
FSUI_CSTR("Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed."),
|
FSUI_CSTR("Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed."),
|
||||||
"UI", "ConfirmShutdown", true);
|
"UI", "ConfirmShutdown", true);
|
||||||
@ -4162,7 +4219,7 @@ void FullscreenUI::DrawInterfaceSettingsPage()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SmallStackString<256> swap_summery;
|
SmallStackString<256> swap_summery;
|
||||||
swap_summery.format(FSUI_FSTR("Uses {} as confirm when using a controller"), ICON_PF_BUTTON_CIRCLE);
|
swap_summery.format(FSUI_FSTR("Uses {} as confirm when using a controller."), ICON_PF_BUTTON_CIRCLE);
|
||||||
if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Swap OK/Cancel in Big Picture Mode"), swap_summery.c_str(),
|
if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Swap OK/Cancel in Big Picture Mode"), swap_summery.c_str(),
|
||||||
(swap_index < std::size(swap_values)) ? Host::TranslateToCString(TR_CONTEXT, swap_names[swap_index]) : FSUI_CSTR("Unknown")))
|
(swap_index < std::size(swap_values)) ? Host::TranslateToCString(TR_CONTEXT, swap_names[swap_index]) : FSUI_CSTR("Unknown")))
|
||||||
{
|
{
|
||||||
@ -4230,6 +4287,8 @@ void FullscreenUI::DrawInterfaceSettingsPage()
|
|||||||
true);
|
true);
|
||||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_POINTER, "Hide Cursor In Fullscreen"),
|
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_POINTER, "Hide Cursor In Fullscreen"),
|
||||||
FSUI_CSTR("Hides the mouse pointer/cursor when the emulator is in fullscreen mode."), "UI", "HideMouseCursor", false);
|
FSUI_CSTR("Hides the mouse pointer/cursor when the emulator is in fullscreen mode."), "UI", "HideMouseCursor", false);
|
||||||
|
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TABLET_SCREEN_BUTTON, "Start Big Picture UI"),
|
||||||
|
FSUI_CSTR("Automatically starts Big Picture Mode instead of the regular Qt interface when PCSX2 launches."), "UI", "StartBigPictureMode", false);
|
||||||
|
|
||||||
MenuHeading(FSUI_CSTR("On-Screen Display"));
|
MenuHeading(FSUI_CSTR("On-Screen Display"));
|
||||||
DrawIntSpinBoxSetting(bsi, FSUI_ICONSTR(ICON_FA_MAGNIFYING_GLASS, "OSD Scale"),
|
DrawIntSpinBoxSetting(bsi, FSUI_ICONSTR(ICON_FA_MAGNIFYING_GLASS, "OSD Scale"),
|
||||||
@ -4268,7 +4327,7 @@ void FullscreenUI::DrawInterfaceSettingsPage()
|
|||||||
FSUI_CSTR("Shows the number of internal video frames displayed per second by the system."),
|
FSUI_CSTR("Shows the number of internal video frames displayed per second by the system."),
|
||||||
"EmuCore/GS", "OsdShowFPS", false);
|
"EmuCore/GS", "OsdShowFPS", false);
|
||||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CLAPPERBOARD, "Show VPS"),
|
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CLAPPERBOARD, "Show VPS"),
|
||||||
FSUI_CSTR("Shows the number of V-syncs performed per second by the system."), "EmuCore/GS", "OsdShowVPS", false);
|
FSUI_CSTR("Shows the number of Vsyncs performed per second by the system."), "EmuCore/GS", "OsdShowVPS", false);
|
||||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_MONITOR_CODE, "Show Resolution"),
|
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_MONITOR_CODE, "Show Resolution"),
|
||||||
FSUI_CSTR("Shows the internal resolution of the game."), "EmuCore/GS", "OsdShowResolution", false);
|
FSUI_CSTR("Shows the internal resolution of the game."), "EmuCore/GS", "OsdShowResolution", false);
|
||||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COMPUTER, "Show Hardware Info"),
|
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COMPUTER, "Show Hardware Info"),
|
||||||
@ -4723,9 +4782,9 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
|
|||||||
FSUI_NSTR("Disabled (Ignore Transfers)"),
|
FSUI_NSTR("Disabled (Ignore Transfers)"),
|
||||||
};
|
};
|
||||||
static constexpr const char* s_screenshot_sizes[] = {
|
static constexpr const char* s_screenshot_sizes[] = {
|
||||||
FSUI_NSTR("Screen Resolution"),
|
FSUI_NSTR("Display Resolution (Aspect Corrected)"),
|
||||||
FSUI_NSTR("Internal Resolution"),
|
FSUI_NSTR("Internal Resolution (Aspect Corrected)"),
|
||||||
FSUI_NSTR("Internal Resolution (Aspect Uncorrected)"),
|
FSUI_NSTR("Internal Resolution (No Aspect Correction)"),
|
||||||
};
|
};
|
||||||
static constexpr const char* s_screenshot_formats[] = {
|
static constexpr const char* s_screenshot_formats[] = {
|
||||||
FSUI_NSTR("PNG"),
|
FSUI_NSTR("PNG"),
|
||||||
@ -4965,7 +5024,7 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
|
|||||||
"UserHacks_native_scaling", 0, s_native_scaling_options, std::size(s_native_scaling_options), true);
|
"UserHacks_native_scaling", 0, s_native_scaling_options, std::size(s_native_scaling_options), true);
|
||||||
DrawIntListSetting(bsi, FSUI_CSTR("Round Sprite"), FSUI_CSTR("Adjusts sprite coordinates."), "EmuCore/GS",
|
DrawIntListSetting(bsi, FSUI_CSTR("Round Sprite"), FSUI_CSTR("Adjusts sprite coordinates."), "EmuCore/GS",
|
||||||
"UserHacks_round_sprite_offset", 0, s_round_sprite_options, std::size(s_round_sprite_options), true);
|
"UserHacks_round_sprite_offset", 0, s_round_sprite_options, std::size(s_round_sprite_options), true);
|
||||||
DrawIntListSetting(bsi, FSUI_CSTR("Bilinear Upscale"),
|
DrawIntListSetting(bsi, FSUI_CSTR("Bilinear Dirty Upscale"),
|
||||||
FSUI_CSTR("Can smooth out textures due to be bilinear filtered when upscaling. E.g. Brave sun glare."), "EmuCore/GS",
|
FSUI_CSTR("Can smooth out textures due to be bilinear filtered when upscaling. E.g. Brave sun glare."), "EmuCore/GS",
|
||||||
"UserHacks_BilinearHack", static_cast<int>(GSBilinearDirtyMode::Automatic), s_bilinear_dirty_options,
|
"UserHacks_BilinearHack", static_cast<int>(GSBilinearDirtyMode::Automatic), s_bilinear_dirty_options,
|
||||||
std::size(s_bilinear_dirty_options), true);
|
std::size(s_bilinear_dirty_options), true);
|
||||||
@ -5141,7 +5200,7 @@ void FullscreenUI::DrawAudioSettingsPage()
|
|||||||
|
|
||||||
DrawEnumSetting(
|
DrawEnumSetting(
|
||||||
bsi, FSUI_ICONSTR(ICON_FA_VOLUME_OFF, "Audio Backend"),
|
bsi, FSUI_ICONSTR(ICON_FA_VOLUME_OFF, "Audio Backend"),
|
||||||
FSUI_CSTR("The audio backend determines how frames produced by the emulator are submitted to the host."), "SPU2/Output",
|
FSUI_CSTR("Determines how audio frames produced by the emulator are submitted to the host."), "SPU2/Output",
|
||||||
"Backend", Pcsx2Config::SPU2Options::DEFAULT_BACKEND, &AudioStream::ParseBackendName, &AudioStream::GetBackendName,
|
"Backend", Pcsx2Config::SPU2Options::DEFAULT_BACKEND, &AudioStream::ParseBackendName, &AudioStream::GetBackendName,
|
||||||
&AudioStream::GetBackendDisplayName, AudioBackend::Count);
|
&AudioStream::GetBackendDisplayName, AudioBackend::Count);
|
||||||
DrawEnumSetting(bsi, FSUI_ICONSTR(ICON_PF_SPEAKER_ALT, "Expansion"),
|
DrawEnumSetting(bsi, FSUI_ICONSTR(ICON_PF_SPEAKER_ALT, "Expansion"),
|
||||||
@ -5196,7 +5255,7 @@ void FullscreenUI::DrawMemoryCardSettingsPage()
|
|||||||
std::string file_key(fmt::format("Slot{}_Filename", port + 1));
|
std::string file_key(fmt::format("Slot{}_Filename", port + 1));
|
||||||
|
|
||||||
DrawToggleSetting(bsi,
|
DrawToggleSetting(bsi,
|
||||||
SmallString::from_format(fmt::runtime(FSUI_ICONSTR_S(ICON_PF_MEMORY_CARD, "Card Enabled", "##card_enabled_{}")), port),
|
SmallString::from_format(fmt::runtime(FSUI_ICONSTR_S(ICON_PF_MEMORY_CARD, "Memory Card Enabled", "##card_enabled_{}")), port),
|
||||||
FSUI_CSTR("If not set, this card will be considered unplugged."), "MemoryCards", enable_key.c_str(), true);
|
FSUI_CSTR("If not set, this card will be considered unplugged."), "MemoryCards", enable_key.c_str(), true);
|
||||||
|
|
||||||
const bool enabled = GetEffectiveBoolSetting(bsi, "MemoryCards", enable_key.c_str(), true);
|
const bool enabled = GetEffectiveBoolSetting(bsi, "MemoryCards", enable_key.c_str(), true);
|
||||||
@ -5300,22 +5359,22 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
const bool network_enabled = GetEffectiveBoolSetting(bsi, "DEV9/Eth", "EthEnable", false);
|
const bool network_enabled = GetEffectiveBoolSetting(bsi, "DEV9/Eth", "EthEnable", false);
|
||||||
|
|
||||||
const std::string current_api = bsi->GetStringValue("DEV9/Eth", "EthApi", "Unset");
|
const std::string current_api = bsi->GetStringValue("DEV9/Eth", "EthApi", "Unset");
|
||||||
|
|
||||||
static std::vector<std::vector<AdapterEntry>> adapter_lists;
|
static std::vector<std::vector<AdapterEntry>> adapter_lists;
|
||||||
static std::vector<Pcsx2Config::DEV9Options::NetApi> api_types;
|
static std::vector<Pcsx2Config::DEV9Options::NetApi> api_types;
|
||||||
static std::vector<std::string> api_display_names;
|
static std::vector<std::string> api_display_names;
|
||||||
static bool adapters_loaded = false;
|
static bool adapters_loaded = false;
|
||||||
|
|
||||||
if (!adapters_loaded && network_enabled)
|
if (!adapters_loaded && network_enabled)
|
||||||
{
|
{
|
||||||
adapter_lists.clear();
|
adapter_lists.clear();
|
||||||
api_types.clear();
|
api_types.clear();
|
||||||
api_display_names.clear();
|
api_display_names.clear();
|
||||||
|
|
||||||
adapter_lists.emplace_back();
|
adapter_lists.emplace_back();
|
||||||
api_types.emplace_back(Pcsx2Config::DEV9Options::NetApi::Unset);
|
api_types.emplace_back(Pcsx2Config::DEV9Options::NetApi::Unset);
|
||||||
api_display_names.emplace_back("Unset");
|
api_display_names.emplace_back("Unset");
|
||||||
|
|
||||||
std::vector<AdapterEntry> pcap_adapters = PCAPAdapter::GetAdapters();
|
std::vector<AdapterEntry> pcap_adapters = PCAPAdapter::GetAdapters();
|
||||||
if (!pcap_adapters.empty())
|
if (!pcap_adapters.empty())
|
||||||
{
|
{
|
||||||
@ -5323,7 +5382,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
std::vector<AdapterEntry> pcap_switched_adapters;
|
std::vector<AdapterEntry> pcap_switched_adapters;
|
||||||
std::set<std::string> seen_bridged_guids;
|
std::set<std::string> seen_bridged_guids;
|
||||||
std::set<std::string> seen_switched_guids;
|
std::set<std::string> seen_switched_guids;
|
||||||
|
|
||||||
for (const auto& adapter : pcap_adapters)
|
for (const auto& adapter : pcap_adapters)
|
||||||
{
|
{
|
||||||
if (adapter.type == Pcsx2Config::DEV9Options::NetApi::PCAP_Bridged)
|
if (adapter.type == Pcsx2Config::DEV9Options::NetApi::PCAP_Bridged)
|
||||||
@ -5343,7 +5402,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort adapters alphabetically by name
|
// Sort adapters alphabetically by name
|
||||||
std::sort(pcap_bridged_adapters.begin(), pcap_bridged_adapters.end(),
|
std::sort(pcap_bridged_adapters.begin(), pcap_bridged_adapters.end(),
|
||||||
[](const AdapterEntry& a, const AdapterEntry& b) { return a.name < b.name; });
|
[](const AdapterEntry& a, const AdapterEntry& b) { return a.name < b.name; });
|
||||||
@ -5364,7 +5423,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
api_display_names.emplace_back("PCAP Switched");
|
api_display_names.emplace_back("PCAP Switched");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::vector<AdapterEntry> tap_adapters = TAPAdapter::GetAdapters();
|
std::vector<AdapterEntry> tap_adapters = TAPAdapter::GetAdapters();
|
||||||
if (!tap_adapters.empty())
|
if (!tap_adapters.empty())
|
||||||
@ -5378,7 +5437,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
api_display_names.emplace_back("TAP");
|
api_display_names.emplace_back("TAP");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<AdapterEntry> socket_adapters = SocketAdapter::GetAdapters();
|
std::vector<AdapterEntry> socket_adapters = SocketAdapter::GetAdapters();
|
||||||
if (!socket_adapters.empty())
|
if (!socket_adapters.empty())
|
||||||
{
|
{
|
||||||
@ -5390,7 +5449,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
api_types.emplace_back(Pcsx2Config::DEV9Options::NetApi::Sockets);
|
api_types.emplace_back(Pcsx2Config::DEV9Options::NetApi::Sockets);
|
||||||
api_display_names.emplace_back("Sockets");
|
api_display_names.emplace_back("Sockets");
|
||||||
}
|
}
|
||||||
|
|
||||||
adapters_loaded = true;
|
adapters_loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5410,7 +5469,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
network_enabled))
|
network_enabled))
|
||||||
{
|
{
|
||||||
ImGuiFullscreen::ChoiceDialogOptions options;
|
ImGuiFullscreen::ChoiceDialogOptions options;
|
||||||
|
|
||||||
for (size_t i = 0; i < api_display_names.size(); i++)
|
for (size_t i = 0; i < api_display_names.size(); i++)
|
||||||
{
|
{
|
||||||
options.emplace_back(api_display_names[i], i == current_api_index);
|
options.emplace_back(api_display_names[i], i == current_api_index);
|
||||||
@ -5428,9 +5487,9 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
const std::string selected_api = Pcsx2Config::DEV9Options::NetApiNames[static_cast<int>(current_api_types[index])];
|
const std::string selected_api = Pcsx2Config::DEV9Options::NetApiNames[static_cast<int>(current_api_types[index])];
|
||||||
const std::string previous_api = bsi->GetStringValue("DEV9/Eth", "EthApi", "Unset");
|
const std::string previous_api = bsi->GetStringValue("DEV9/Eth", "EthApi", "Unset");
|
||||||
const std::string previous_device = bsi->GetStringValue("DEV9/Eth", "EthDevice", "");
|
const std::string previous_device = bsi->GetStringValue("DEV9/Eth", "EthDevice", "");
|
||||||
|
|
||||||
bsi->SetStringValue("DEV9/Eth", "EthApi", selected_api.c_str());
|
bsi->SetStringValue("DEV9/Eth", "EthApi", selected_api.c_str());
|
||||||
|
|
||||||
std::string new_device = "";
|
std::string new_device = "";
|
||||||
if (index < static_cast<s32>(current_adapter_lists.size()))
|
if (index < static_cast<s32>(current_adapter_lists.size()))
|
||||||
{
|
{
|
||||||
@ -5455,10 +5514,10 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
new_device = new_adapter_list[0].guid;
|
new_device = new_adapter_list[0].guid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bsi->SetStringValue("DEV9/Eth", "EthDevice", new_device.c_str());
|
bsi->SetStringValue("DEV9/Eth", "EthDevice", new_device.c_str());
|
||||||
SetSettingsChanged(bsi);
|
SetSettingsChanged(bsi);
|
||||||
|
|
||||||
CloseChoiceDialog();
|
CloseChoiceDialog();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -5481,7 +5540,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device_display.empty())
|
if (device_display.empty())
|
||||||
device_display = current_device;
|
device_display = current_device;
|
||||||
}
|
}
|
||||||
@ -5528,7 +5587,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
if (index < static_cast<s32>(current_adapter_list.size()))
|
if (index < static_cast<s32>(current_adapter_list.size()))
|
||||||
{
|
{
|
||||||
const auto& selected_adapter = current_adapter_list[index];
|
const auto& selected_adapter = current_adapter_list[index];
|
||||||
|
|
||||||
auto lock = Host::GetSettingsLock();
|
auto lock = Host::GetSettingsLock();
|
||||||
bsi->SetStringValue("DEV9/Eth", "EthApi", current_api_choice.c_str());
|
bsi->SetStringValue("DEV9/Eth", "EthApi", current_api_choice.c_str());
|
||||||
bsi->SetStringValue("DEV9/Eth", "EthDevice", selected_adapter.guid.c_str());
|
bsi->SetStringValue("DEV9/Eth", "EthDevice", selected_adapter.guid.c_str());
|
||||||
@ -5574,7 +5633,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
FSUI_CSTR("Automatically determine the subnet mask based on the IP address class."),
|
FSUI_CSTR("Automatically determine the subnet mask based on the IP address class."),
|
||||||
"DEV9/Eth", "AutoMask", true, ip_settings_enabled && subnet_can_be_edited);
|
"DEV9/Eth", "AutoMask", true, ip_settings_enabled && subnet_can_be_edited);
|
||||||
DrawIPAddressSetting(bsi, FSUI_ICONSTR(ICON_FA_NETWORK_WIRED, "Subnet Mask"),
|
DrawIPAddressSetting(bsi, FSUI_ICONSTR(ICON_FA_NETWORK_WIRED, "Subnet Mask"),
|
||||||
FSUI_CSTR("Subnet mask for the PS2 virtual network adapter."), "DEV9/Eth", "Mask", "0.0.0.0",
|
FSUI_CSTR("Subnet mask for the PS2 virtual network adapter."), "DEV9/Eth", "Mask", "0.0.0.0",
|
||||||
ip_settings_enabled && subnet_can_be_edited && !mask_auto, LAYOUT_MENU_BUTTON_HEIGHT, g_large_font, g_medium_font, IPAddressType::SubnetMask);
|
ip_settings_enabled && subnet_can_be_edited && !mask_auto, LAYOUT_MENU_BUTTON_HEIGHT, g_large_font, g_medium_font, IPAddressType::SubnetMask);
|
||||||
|
|
||||||
const bool gateway_auto = GetEffectiveBoolSetting(bsi, "DEV9/Eth", "AutoGateway", true);
|
const bool gateway_auto = GetEffectiveBoolSetting(bsi, "DEV9/Eth", "AutoGateway", true);
|
||||||
@ -5632,7 +5691,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
{
|
{
|
||||||
const std::string full_path = fd.FileName;
|
const std::string full_path = fd.FileName;
|
||||||
const std::string filename = std::string(Path::GetFileName(full_path));
|
const std::string filename = std::string(Path::GetFileName(full_path));
|
||||||
|
|
||||||
// Get file size and determine LBA mode
|
// Get file size and determine LBA mode
|
||||||
const s64 file_size = FileSystem::GetPathFileSize(full_path.c_str());
|
const s64 file_size = FileSystem::GetPathFileSize(full_path.c_str());
|
||||||
if (file_size > 0)
|
if (file_size > 0)
|
||||||
@ -5640,8 +5699,8 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
const int size_gb = static_cast<int>(file_size / _1gb);
|
const int size_gb = static_cast<int>(file_size / _1gb);
|
||||||
const bool uses_lba48 = (file_size > static_cast<s64>(120) * _1gb);
|
const bool uses_lba48 = (file_size > static_cast<s64>(120) * _1gb);
|
||||||
const std::string lba_mode = uses_lba48 ? "LBA48" : "LBA28";
|
const std::string lba_mode = uses_lba48 ? "LBA48" : "LBA28";
|
||||||
|
|
||||||
choices.emplace_back(fmt::format("{} ({} GB, {})", filename, size_gb, lba_mode),
|
choices.emplace_back(fmt::format("{} ({} GB, {})", filename, size_gb, lba_mode),
|
||||||
hdd_selection == full_path);
|
hdd_selection == full_path);
|
||||||
values.emplace_back(full_path);
|
values.emplace_back(full_path);
|
||||||
}
|
}
|
||||||
@ -5661,7 +5720,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
if (values[index] == "__browse__")
|
if (values[index] == "__browse__")
|
||||||
{
|
{
|
||||||
CloseChoiceDialog();
|
CloseChoiceDialog();
|
||||||
|
|
||||||
OpenFileSelector(FSUI_ICONSTR(ICON_FA_HARD_DRIVE, "Select HDD Image File"), false,
|
OpenFileSelector(FSUI_ICONSTR(ICON_FA_HARD_DRIVE, "Select HDD Image File"), false,
|
||||||
[game_settings](const std::string& path) {
|
[game_settings](const std::string& path) {
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
@ -5677,7 +5736,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
else if (values[index] == "__create__")
|
else if (values[index] == "__create__")
|
||||||
{
|
{
|
||||||
CloseChoiceDialog();
|
CloseChoiceDialog();
|
||||||
|
|
||||||
std::vector<std::pair<std::string, int>> size_options = {
|
std::vector<std::pair<std::string, int>> size_options = {
|
||||||
{"40 GB (Recommended)", 40},
|
{"40 GB (Recommended)", 40},
|
||||||
{"80 GB", 80},
|
{"80 GB", 80},
|
||||||
@ -5702,7 +5761,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
if (size_values[size_index] == -1)
|
if (size_values[size_index] == -1)
|
||||||
{
|
{
|
||||||
CloseChoiceDialog();
|
CloseChoiceDialog();
|
||||||
|
|
||||||
OpenInputStringDialog(
|
OpenInputStringDialog(
|
||||||
FSUI_ICONSTR(ICON_FA_PEN_TO_SQUARE, "Custom HDD Size"),
|
FSUI_ICONSTR(ICON_FA_PEN_TO_SQUARE, "Custom HDD Size"),
|
||||||
FSUI_STR("Enter custom HDD size in gigabytes (40–2000):"),
|
FSUI_STR("Enter custom HDD size in gigabytes (40–2000):"),
|
||||||
@ -5711,7 +5770,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
[game_settings](std::string input) {
|
[game_settings](std::string input) {
|
||||||
if (input.empty())
|
if (input.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::optional<int> custom_size_opt = StringUtil::FromChars<int>(input);
|
std::optional<int> custom_size_opt = StringUtil::FromChars<int>(input);
|
||||||
if (!custom_size_opt.has_value())
|
if (!custom_size_opt.has_value())
|
||||||
{
|
{
|
||||||
@ -5719,17 +5778,17 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int custom_size_gb = custom_size_opt.value();
|
int custom_size_gb = custom_size_opt.value();
|
||||||
|
|
||||||
if (custom_size_gb < 40 || custom_size_gb > 2000)
|
if (custom_size_gb < 40 || custom_size_gb > 2000)
|
||||||
{
|
{
|
||||||
ShowToast(std::string(), FSUI_STR("HDD size must be between 40 GB and 2000 GB."));
|
ShowToast(std::string(), FSUI_STR("HDD size must be between 40 GB and 2000 GB."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool lba48 = (custom_size_gb > 120);
|
const bool lba48 = (custom_size_gb > 120);
|
||||||
const std::string filename = fmt::format("DEV9hdd_{}GB_{}.raw", custom_size_gb, lba48 ? "LBA48" : "LBA28");
|
const std::string filename = fmt::format("DEV9hdd_{}GB_{}.raw", custom_size_gb, lba48 ? "LBA48" : "LBA28");
|
||||||
const std::string filepath = Path::Combine(EmuFolders::DataRoot, filename);
|
const std::string filepath = Path::Combine(EmuFolders::DataRoot, filename);
|
||||||
|
|
||||||
if (FileSystem::FileExists(filepath.c_str()))
|
if (FileSystem::FileExists(filepath.c_str()))
|
||||||
{
|
{
|
||||||
OpenConfirmMessageDialog(
|
OpenConfirmMessageDialog(
|
||||||
@ -5762,10 +5821,10 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
|
|
||||||
const int size_gb = size_values[size_index];
|
const int size_gb = size_values[size_index];
|
||||||
const bool lba48 = (size_gb > 120);
|
const bool lba48 = (size_gb > 120);
|
||||||
|
|
||||||
const std::string filename = fmt::format("DEV9hdd_{}GB_{}.raw", size_gb, lba48 ? "LBA48" : "LBA28");
|
const std::string filename = fmt::format("DEV9hdd_{}GB_{}.raw", size_gb, lba48 ? "LBA48" : "LBA28");
|
||||||
const std::string filepath = Path::Combine(EmuFolders::DataRoot, filename);
|
const std::string filepath = Path::Combine(EmuFolders::DataRoot, filename);
|
||||||
|
|
||||||
if (FileSystem::FileExists(filepath.c_str()))
|
if (FileSystem::FileExists(filepath.c_str()))
|
||||||
{
|
{
|
||||||
OpenConfirmMessageDialog(
|
OpenConfirmMessageDialog(
|
||||||
@ -5790,7 +5849,7 @@ void FullscreenUI::DrawNetworkHDDSettingsPage()
|
|||||||
SetSettingsChanged(bsi);
|
SetSettingsChanged(bsi);
|
||||||
FullscreenUI::CreateHardDriveWithProgress(filepath, size_gb, lba48);
|
FullscreenUI::CreateHardDriveWithProgress(filepath, size_gb, lba48);
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseChoiceDialog();
|
CloseChoiceDialog();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -6613,7 +6672,7 @@ void FullscreenUI::DrawAdvancedSettingsPage()
|
|||||||
FSUI_CSTR("Performs just-in-time binary translation of 32-bit MIPS-I machine code to native code."), "EmuCore/CPU/Recompiler",
|
FSUI_CSTR("Performs just-in-time binary translation of 32-bit MIPS-I machine code to native code."), "EmuCore/CPU/Recompiler",
|
||||||
"EnableIOP", true);
|
"EnableIOP", true);
|
||||||
|
|
||||||
MenuHeading(FSUI_CSTR("Savestate"));
|
MenuHeading(FSUI_CSTR("Save State Management"));
|
||||||
DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_BOX_OPEN, "Compression Method"), FSUI_CSTR("Sets the compression algorithm for savestate."), "EmuCore",
|
DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_BOX_OPEN, "Compression Method"), FSUI_CSTR("Sets the compression algorithm for savestate."), "EmuCore",
|
||||||
"SavestateCompressionType", static_cast<int>(SavestateCompressionMethod::Zstandard), s_savestate_compression_type, std::size(s_savestate_compression_type), true);
|
"SavestateCompressionType", static_cast<int>(SavestateCompressionMethod::Zstandard), s_savestate_compression_type, std::size(s_savestate_compression_type), true);
|
||||||
DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_COMPRESS, "Compression Level"), FSUI_CSTR("Sets the compression level for savestate."), "EmuCore",
|
DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_COMPRESS, "Compression Level"), FSUI_CSTR("Sets the compression level for savestate."), "EmuCore",
|
||||||
@ -6631,7 +6690,7 @@ void FullscreenUI::DrawPatchesOrCheatsSettingsPage(bool cheats)
|
|||||||
{
|
{
|
||||||
SettingsInterface* bsi = GetEditingSettingsInterface();
|
SettingsInterface* bsi = GetEditingSettingsInterface();
|
||||||
|
|
||||||
const Patch::PatchInfoList& patch_list = cheats ? s_game_cheats_list : s_game_patch_list;
|
const std::vector<Patch::PatchInfo>& patch_list = cheats ? s_game_cheats_list : s_game_patch_list;
|
||||||
std::vector<std::string>& enable_list = cheats ? s_enabled_game_cheat_cache : s_enabled_game_patch_cache;
|
std::vector<std::string>& enable_list = cheats ? s_enabled_game_cheat_cache : s_enabled_game_patch_cache;
|
||||||
const char* section = cheats ? Patch::CHEATS_CONFIG_SECTION : Patch::PATCHES_CONFIG_SECTION;
|
const char* section = cheats ? Patch::CHEATS_CONFIG_SECTION : Patch::PATCHES_CONFIG_SECTION;
|
||||||
const bool master_enable = cheats ? GetEffectiveBoolSetting(bsi, "EmuCore", "EnableCheats", false) : true;
|
const bool master_enable = cheats ? GetEffectiveBoolSetting(bsi, "EmuCore", "EnableCheats", false) : true;
|
||||||
@ -6739,7 +6798,7 @@ void FullscreenUI::DrawGameFixesSettingsPage()
|
|||||||
FSUI_CSTR("Known to affect following games: Bleach Blade Battlers, Growlanser II and III, Wizardry."), "EmuCore/Gamefixes",
|
FSUI_CSTR("Known to affect following games: Bleach Blade Battlers, Growlanser II and III, Wizardry."), "EmuCore/Gamefixes",
|
||||||
"OPHFlagHack", false);
|
"OPHFlagHack", false);
|
||||||
DrawToggleSetting(
|
DrawToggleSetting(
|
||||||
bsi, FSUI_CSTR("Emulate GIF FIFO"), FSUI_CSTR("Correct but slower. Known to affect the following games: Fifa Street 2."), "EmuCore/Gamefixes", "GIFFIFOHack", false);
|
bsi, FSUI_CSTR("Emulate GIF FIFO"), FSUI_CSTR("Correct but slower. Known to affect the following games: FIFA Street 2."), "EmuCore/Gamefixes", "GIFFIFOHack", false);
|
||||||
DrawToggleSetting(bsi, FSUI_CSTR("DMA Busy Hack"),
|
DrawToggleSetting(bsi, FSUI_CSTR("DMA Busy Hack"),
|
||||||
FSUI_CSTR("Known to affect following games: Mana Khemia 1, Metal Saga, Pilot Down Behind Enemy Lines."), "EmuCore/Gamefixes",
|
FSUI_CSTR("Known to affect following games: Mana Khemia 1, Metal Saga, Pilot Down Behind Enemy Lines."), "EmuCore/Gamefixes",
|
||||||
"DMABusyHack", false);
|
"DMABusyHack", false);
|
||||||
@ -7343,9 +7402,9 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
|
|||||||
false, is_loading ? !Achievements::IsHardcoreModeActive() : true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY))
|
false, is_loading ? !Achievements::IsHardcoreModeActive() : true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY))
|
||||||
{
|
{
|
||||||
if (is_loading)
|
if (is_loading)
|
||||||
DoLoadState(std::move(entry.path));
|
DoLoadState(std::move(entry.path), entry.slot, false);
|
||||||
else
|
else
|
||||||
Host::RunOnCPUThread([slot = entry.slot]() { VMManager::SaveStateToSlot(slot); });
|
DoSaveState(entry.slot);
|
||||||
|
|
||||||
CloseSaveStateSelector();
|
CloseSaveStateSelector();
|
||||||
ReturnToMainWindow();
|
ReturnToMainWindow();
|
||||||
@ -7481,9 +7540,9 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
|
|||||||
if (pressed)
|
if (pressed)
|
||||||
{
|
{
|
||||||
if (is_loading)
|
if (is_loading)
|
||||||
DoLoadState(entry.path);
|
DoLoadState(entry.path, entry.slot, false);
|
||||||
else
|
else
|
||||||
Host::RunOnCPUThread([slot = entry.slot]() { VMManager::SaveStateToSlot(slot); });
|
DoSaveState(entry.slot);
|
||||||
|
|
||||||
CloseSaveStateSelector();
|
CloseSaveStateSelector();
|
||||||
ReturnToMainWindow();
|
ReturnToMainWindow();
|
||||||
@ -7637,19 +7696,16 @@ void FullscreenUI::DrawResumeStateSelector()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullscreenUI::DoLoadState(std::string path)
|
void FullscreenUI::DoLoadState(std::string path, std::optional<s32> slot, bool backup)
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([boot_path = s_save_state_selector_game_path, path = std::move(path)]() {
|
std::string boot_path = s_save_state_selector_game_path;
|
||||||
|
Host::RunOnCPUThread([boot_path = std::move(boot_path), path = std::move(path), slot, backup]() {
|
||||||
if (VMManager::HasValidVM())
|
if (VMManager::HasValidVM())
|
||||||
{
|
{
|
||||||
Error error;
|
Error error;
|
||||||
if (!VMManager::LoadState(path.c_str(), &error))
|
if (!VMManager::LoadState(path.c_str(), &error))
|
||||||
{
|
{
|
||||||
MTGS::RunOnGSThread([error = std::move(error)]() {
|
ReportStateLoadError(error.GetDescription(), slot, backup);
|
||||||
ImGuiFullscreen::OpenInfoMessageDialog(
|
|
||||||
FSUI_ICONSTR(ICON_FA_TRIANGLE_EXCLAMATION, "Failed to Load State"),
|
|
||||||
error.GetDescription());
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7666,6 +7722,15 @@ void FullscreenUI::DoLoadState(std::string path)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FullscreenUI::DoSaveState(s32 slot)
|
||||||
|
{
|
||||||
|
Host::RunOnCPUThread([slot]() {
|
||||||
|
VMManager::SaveStateToSlot(slot, true, [slot](const std::string& error) {
|
||||||
|
ReportStateSaveError(error, slot);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void FullscreenUI::PopulateGameListEntryList()
|
void FullscreenUI::PopulateGameListEntryList()
|
||||||
{
|
{
|
||||||
const int sort = Host::GetBaseIntSettingValue("UI", "FullscreenUIGameSort", 0);
|
const int sort = Host::GetBaseIntSettingValue("UI", "FullscreenUIGameSort", 0);
|
||||||
@ -7854,7 +7919,7 @@ void FullscreenUI::DrawGameListWindow()
|
|||||||
void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||||
{
|
{
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, UIBackgroundColor);
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, UIBackgroundColor);
|
||||||
|
|
||||||
if (!BeginFullscreenColumns(nullptr, heading_size.y, true, true))
|
if (!BeginFullscreenColumns(nullptr, heading_size.y, true, true))
|
||||||
{
|
{
|
||||||
EndFullscreenColumns();
|
EndFullscreenColumns();
|
||||||
@ -8140,7 +8205,7 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
|
|||||||
|
|
||||||
const bool show_titles = Host::GetBaseBoolSettingValue("UI", "FullscreenUIShowGameGridTitles", true);
|
const bool show_titles = Host::GetBaseBoolSettingValue("UI", "FullscreenUIShowGameGridTitles", true);
|
||||||
|
|
||||||
if (show_titles)
|
if (show_titles)
|
||||||
{
|
{
|
||||||
const ImRect title_bb(ImVec2(bb.Min.x, bb.Min.y + image_height + title_spacing), bb.Max);
|
const ImRect title_bb(ImVec2(bb.Min.x, bb.Min.y + image_height + title_spacing), bb.Max);
|
||||||
const std::string_view title(std::string_view(entry->GetTitle(true)).substr(0, 31));
|
const std::string_view title(std::string_view(entry->GetTitle(true)).substr(0, 31));
|
||||||
@ -8706,7 +8771,7 @@ void FullscreenUI::DrawAchievementsLoginWindow()
|
|||||||
|
|
||||||
ImGui::PushTextWrapPos(content_width);
|
ImGui::PushTextWrapPos(content_width);
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 0.8f, 0.8f, 1.0f));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 0.8f, 0.8f, 1.0f));
|
||||||
ImGui::TextWrapped("%s", FSUI_CSTR("Please enter your user name and password for retroachievements.org below. \n\n Your password will not be saved in PCSX2, an access token will be generated and used instead."));
|
ImGui::TextWrapped("%s", FSUI_CSTR("Please enter your user name and password for retroachievements.org below.\n\nYour password will not be saved in PCSX2, an access token will be generated and used instead."));
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
ImGui::PopTextWrapPos();
|
ImGui::PopTextWrapPos();
|
||||||
|
|
||||||
@ -9167,6 +9232,75 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
|
|||||||
EndMenuButtons();
|
EndMenuButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FullscreenUI::ReportStateLoadError(const std::string& message, std::optional<s32> slot, bool backup)
|
||||||
|
{
|
||||||
|
MTGS::RunOnGSThread([message, slot, backup]() {
|
||||||
|
const bool prompt_on_error = Host::GetBaseBoolSettingValue("UI", "PromptOnStateLoadSaveFailure", true);
|
||||||
|
if (!prompt_on_error || !ImGuiManager::InitializeFullscreenUI())
|
||||||
|
{
|
||||||
|
SaveState_ReportLoadErrorOSD(message, slot, backup);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string title;
|
||||||
|
if (slot.has_value())
|
||||||
|
{
|
||||||
|
if (backup)
|
||||||
|
title = fmt::format(FSUI_FSTR("Failed to Load State From Backup Slot {}"), *slot);
|
||||||
|
else
|
||||||
|
title = fmt::format(FSUI_FSTR("Failed to Load State From Slot {}"), *slot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
title = FSUI_STR("Failed to Load State");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiFullscreen::InfoMessageDialogCallback callback;
|
||||||
|
if (VMManager::GetState() == VMState::Running)
|
||||||
|
{
|
||||||
|
Host::RunOnCPUThread([]() { VMManager::SetPaused(true); });
|
||||||
|
callback = []() {
|
||||||
|
Host::RunOnCPUThread([]() { VMManager::SetPaused(false); });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiFullscreen::OpenInfoMessageDialog(
|
||||||
|
fmt::format("{} {}", ICON_FA_TRIANGLE_EXCLAMATION, title),
|
||||||
|
std::move(message), std::move(callback));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void FullscreenUI::ReportStateSaveError(const std::string& message, std::optional<s32> slot)
|
||||||
|
{
|
||||||
|
MTGS::RunOnGSThread([message, slot]() {
|
||||||
|
const bool prompt_on_error = Host::GetBaseBoolSettingValue("UI", "PromptOnStateLoadSaveFailure", true);
|
||||||
|
if (!prompt_on_error || !ImGuiManager::InitializeFullscreenUI())
|
||||||
|
{
|
||||||
|
SaveState_ReportSaveErrorOSD(message, slot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string title;
|
||||||
|
if (slot.has_value())
|
||||||
|
title = fmt::format(FSUI_FSTR("Failed to Save State To Slot {}"), *slot);
|
||||||
|
else
|
||||||
|
title = FSUI_STR("Failed to Save State");
|
||||||
|
|
||||||
|
ImGuiFullscreen::InfoMessageDialogCallback callback;
|
||||||
|
if (VMManager::GetState() == VMState::Running)
|
||||||
|
{
|
||||||
|
Host::RunOnCPUThread([]() { VMManager::SetPaused(true); });
|
||||||
|
callback = []() {
|
||||||
|
Host::RunOnCPUThread([]() { VMManager::SetPaused(false); });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiFullscreen::OpenInfoMessageDialog(
|
||||||
|
fmt::format("{} {}", ICON_FA_TRIANGLE_EXCLAMATION, title),
|
||||||
|
std::move(message), std::move(callback));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Translation String Area
|
// Translation String Area
|
||||||
// To avoid having to type T_RANSLATE("FullscreenUI", ...) everywhere, we use the shorter macros at the top
|
// To avoid having to type T_RANSLATE("FullscreenUI", ...) everywhere, we use the shorter macros at the top
|
||||||
@ -9226,6 +9360,8 @@ TRANSLATE_NOOP("FullscreenUI", "Reset System");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode will not be enabled until the system is reset. Do you want to reset the system now?");
|
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode will not be enabled until the system is reset. Do you want to reset the system now?");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "This game has no achievements.");
|
TRANSLATE_NOOP("FullscreenUI", "This game has no achievements.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "This game has no leaderboards.");
|
TRANSLATE_NOOP("FullscreenUI", "This game has no leaderboards.");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Failed to Save State");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Game List");
|
TRANSLATE_NOOP("FullscreenUI", "Game List");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Launch a game from images scanned from your game directories.");
|
TRANSLATE_NOOP("FullscreenUI", "Launch a game from images scanned from your game directories.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Start Game");
|
TRANSLATE_NOOP("FullscreenUI", "Start Game");
|
||||||
@ -9271,7 +9407,7 @@ TRANSLATE_NOOP("FullscreenUI", "Selects the color style to be used for Big Pictu
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "When Big Picture mode is started, the game list will be displayed instead of the main menu.");
|
TRANSLATE_NOOP("FullscreenUI", "When Big Picture mode is started, the game list will be displayed instead of the main menu.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Show a save state selector UI when switching slots instead of showing a notification bubble.");
|
TRANSLATE_NOOP("FullscreenUI", "Show a save state selector UI when switching slots instead of showing a notification bubble.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Background");
|
TRANSLATE_NOOP("FullscreenUI", "Background");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Select a custom background image to use in Big Picture Mode menus.");
|
TRANSLATE_NOOP("FullscreenUI", "Select a custom background image to use in Big Picture Mode menus.\n\nSupported formats: PNG, JPG, JPEG, BMP.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Removes the custom background image.");
|
TRANSLATE_NOOP("FullscreenUI", "Removes the custom background image.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Sets the transparency of the custom background image.");
|
TRANSLATE_NOOP("FullscreenUI", "Sets the transparency of the custom background image.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Select how to display the background image.");
|
TRANSLATE_NOOP("FullscreenUI", "Select how to display the background image.");
|
||||||
@ -9281,6 +9417,7 @@ TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a game is started.");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you minimize the window or switch to another application, and unpauses when you switch back.");
|
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you minimize the window or switch to another application, and unpauses when you switch back.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a controller with bindings is disconnected.");
|
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a controller with bindings is disconnected.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you open the quick menu, and unpauses when you close it.");
|
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you open the quick menu, and unpauses when you close it.");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Display a modal dialog when a save state load/save operation fails.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed.");
|
TRANSLATE_NOOP("FullscreenUI", "Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Automatically saves the emulator state when powering down or exiting. You can then resume directly from where you left off next time.");
|
TRANSLATE_NOOP("FullscreenUI", "Automatically saves the emulator state when powering down or exiting. You can then resume directly from where you left off next time.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Creates a backup copy of a save state if it already exists when the save is created. The backup copy has a .backup suffix");
|
TRANSLATE_NOOP("FullscreenUI", "Creates a backup copy of a save state if it already exists when the save is created. The backup copy has a .backup suffix");
|
||||||
@ -9290,6 +9427,7 @@ TRANSLATE_NOOP("FullscreenUI", "Game Display");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Automatically switches to fullscreen mode when a game is started.");
|
TRANSLATE_NOOP("FullscreenUI", "Automatically switches to fullscreen mode when a game is started.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Switches between full screen and windowed when the window is double-clicked.");
|
TRANSLATE_NOOP("FullscreenUI", "Switches between full screen and windowed when the window is double-clicked.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Hides the mouse pointer/cursor when the emulator is in fullscreen mode.");
|
TRANSLATE_NOOP("FullscreenUI", "Hides the mouse pointer/cursor when the emulator is in fullscreen mode.");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Automatically starts Big Picture Mode instead of the regular Qt interface when PCSX2 launches.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "On-Screen Display");
|
TRANSLATE_NOOP("FullscreenUI", "On-Screen Display");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Determines how large the on-screen messages and monitors are.");
|
TRANSLATE_NOOP("FullscreenUI", "Determines how large the on-screen messages and monitors are.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "%d%%");
|
TRANSLATE_NOOP("FullscreenUI", "%d%%");
|
||||||
@ -9298,7 +9436,7 @@ TRANSLATE_NOOP("FullscreenUI", "Determines where performance statistics are posi
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Shows the current PCSX2 version.");
|
TRANSLATE_NOOP("FullscreenUI", "Shows the current PCSX2 version.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Shows the current emulation speed of the system as a percentage.");
|
TRANSLATE_NOOP("FullscreenUI", "Shows the current emulation speed of the system as a percentage.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Shows the number of internal video frames displayed per second by the system.");
|
TRANSLATE_NOOP("FullscreenUI", "Shows the number of internal video frames displayed per second by the system.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Shows the number of V-syncs performed per second by the system.");
|
TRANSLATE_NOOP("FullscreenUI", "Shows the number of Vsyncs performed per second by the system.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Shows the internal resolution of the game.");
|
TRANSLATE_NOOP("FullscreenUI", "Shows the internal resolution of the game.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Shows the current system CPU and GPU information.");
|
TRANSLATE_NOOP("FullscreenUI", "Shows the current system CPU and GPU information.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Shows statistics about the emulated GS such as primitives and draw calls.");
|
TRANSLATE_NOOP("FullscreenUI", "Shows statistics about the emulated GS such as primitives and draw calls.");
|
||||||
@ -9410,7 +9548,7 @@ TRANSLATE_NOOP("FullscreenUI", "Native Scaling");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Attempt to do rescaling at native resolution.");
|
TRANSLATE_NOOP("FullscreenUI", "Attempt to do rescaling at native resolution.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Round Sprite");
|
TRANSLATE_NOOP("FullscreenUI", "Round Sprite");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Adjusts sprite coordinates.");
|
TRANSLATE_NOOP("FullscreenUI", "Adjusts sprite coordinates.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Bilinear Upscale");
|
TRANSLATE_NOOP("FullscreenUI", "Bilinear Dirty Upscale");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Can smooth out textures due to be bilinear filtered when upscaling. E.g. Brave sun glare.");
|
TRANSLATE_NOOP("FullscreenUI", "Can smooth out textures due to be bilinear filtered when upscaling. E.g. Brave sun glare.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Texture Offset X");
|
TRANSLATE_NOOP("FullscreenUI", "Texture Offset X");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Adjusts target texture offsets.");
|
TRANSLATE_NOOP("FullscreenUI", "Adjusts target texture offsets.");
|
||||||
@ -9476,7 +9614,7 @@ TRANSLATE_NOOP("FullscreenUI", "Controls the volume of the audio played on the h
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Controls the volume of the audio played on the host when fast forwarding.");
|
TRANSLATE_NOOP("FullscreenUI", "Controls the volume of the audio played on the host when fast forwarding.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Prevents the emulator from producing any audible sound.");
|
TRANSLATE_NOOP("FullscreenUI", "Prevents the emulator from producing any audible sound.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Backend Settings");
|
TRANSLATE_NOOP("FullscreenUI", "Backend Settings");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "The audio backend determines how frames produced by the emulator are submitted to the host.");
|
TRANSLATE_NOOP("FullscreenUI", "Determines how audio frames produced by the emulator are submitted to the host.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Determines how audio is expanded from stereo to surround for supported games.");
|
TRANSLATE_NOOP("FullscreenUI", "Determines how audio is expanded from stereo to surround for supported games.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Changes when SPU samples are generated relative to system emulation.");
|
TRANSLATE_NOOP("FullscreenUI", "Changes when SPU samples are generated relative to system emulation.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Determines the amount of audio buffered before being pulled by the host API.");
|
TRANSLATE_NOOP("FullscreenUI", "Determines the amount of audio buffered before being pulled by the host API.");
|
||||||
@ -9570,7 +9708,7 @@ TRANSLATE_NOOP("FullscreenUI", "Runs VU1 instantly. Provides a modest speed impr
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "I/O Processor");
|
TRANSLATE_NOOP("FullscreenUI", "I/O Processor");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Enable IOP Recompiler");
|
TRANSLATE_NOOP("FullscreenUI", "Enable IOP Recompiler");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Performs just-in-time binary translation of 32-bit MIPS-I machine code to native code.");
|
TRANSLATE_NOOP("FullscreenUI", "Performs just-in-time binary translation of 32-bit MIPS-I machine code to native code.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Savestate");
|
TRANSLATE_NOOP("FullscreenUI", "Save State Management");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Sets the compression algorithm for savestate.");
|
TRANSLATE_NOOP("FullscreenUI", "Sets the compression algorithm for savestate.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Sets the compression level for savestate.");
|
TRANSLATE_NOOP("FullscreenUI", "Sets the compression level for savestate.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Graphics");
|
TRANSLATE_NOOP("FullscreenUI", "Graphics");
|
||||||
@ -9600,7 +9738,7 @@ TRANSLATE_NOOP("FullscreenUI", "Good for cache emulation problems. Known to affe
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "OPH Flag Hack");
|
TRANSLATE_NOOP("FullscreenUI", "OPH Flag Hack");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Known to affect following games: Bleach Blade Battlers, Growlanser II and III, Wizardry.");
|
TRANSLATE_NOOP("FullscreenUI", "Known to affect following games: Bleach Blade Battlers, Growlanser II and III, Wizardry.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Emulate GIF FIFO");
|
TRANSLATE_NOOP("FullscreenUI", "Emulate GIF FIFO");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Correct but slower. Known to affect the following games: Fifa Street 2.");
|
TRANSLATE_NOOP("FullscreenUI", "Correct but slower. Known to affect the following games: FIFA Street 2.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "DMA Busy Hack");
|
TRANSLATE_NOOP("FullscreenUI", "DMA Busy Hack");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Known to affect following games: Mana Khemia 1, Metal Saga, Pilot Down Behind Enemy Lines.");
|
TRANSLATE_NOOP("FullscreenUI", "Known to affect following games: Mana Khemia 1, Metal Saga, Pilot Down Behind Enemy Lines.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Delay VIF1 Stalls");
|
TRANSLATE_NOOP("FullscreenUI", "Delay VIF1 Stalls");
|
||||||
@ -9647,7 +9785,7 @@ TRANSLATE_NOOP("FullscreenUI", "PCSX2 is a free and open-source PlayStation 2 (P
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "PlayStation 2 and PS2 are registered trademarks of Sony Interactive Entertainment. This application is not affiliated in any way with Sony Interactive Entertainment.");
|
TRANSLATE_NOOP("FullscreenUI", "PlayStation 2 and PS2 are registered trademarks of Sony Interactive Entertainment. This application is not affiliated in any way with Sony Interactive Entertainment.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Version: %s");
|
TRANSLATE_NOOP("FullscreenUI", "Version: %s");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "RetroAchievements");
|
TRANSLATE_NOOP("FullscreenUI", "RetroAchievements");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Please enter your user name and password for retroachievements.org below. \n\n Your password will not be saved in PCSX2, an access token will be generated and used instead.");
|
TRANSLATE_NOOP("FullscreenUI", "Please enter your user name and password for retroachievements.org below.\n\nYour password will not be saved in PCSX2, an access token will be generated and used instead.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Username");
|
TRANSLATE_NOOP("FullscreenUI", "Username");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Password");
|
TRANSLATE_NOOP("FullscreenUI", "Password");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Logging in...");
|
TRANSLATE_NOOP("FullscreenUI", "Logging in...");
|
||||||
@ -9679,7 +9817,7 @@ TRANSLATE_NOOP("FullscreenUI", "Automatic mapping completed for {}.");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Automatic mapping failed for {}.");
|
TRANSLATE_NOOP("FullscreenUI", "Automatic mapping failed for {}.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Game settings initialized with global settings for '{}'.");
|
TRANSLATE_NOOP("FullscreenUI", "Game settings initialized with global settings for '{}'.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Game settings have been cleared for '{}'.");
|
TRANSLATE_NOOP("FullscreenUI", "Game settings have been cleared for '{}'.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Uses {} as confirm when using a controller");
|
TRANSLATE_NOOP("FullscreenUI", "Uses {} as confirm when using a controller.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Swaps both {}/{} (When Swap OK/Cancel is set to automatic) and {}/{} buttons");
|
TRANSLATE_NOOP("FullscreenUI", "Swaps both {}/{} (When Swap OK/Cancel is set to automatic) and {}/{} buttons");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Slot {}");
|
TRANSLATE_NOOP("FullscreenUI", "Slot {}");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "{} (Current)");
|
TRANSLATE_NOOP("FullscreenUI", "{} (Current)");
|
||||||
@ -9715,6 +9853,9 @@ TRANSLATE_NOOP("FullscreenUI", "Last Played: {}");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Size: {:.2f} MB");
|
TRANSLATE_NOOP("FullscreenUI", "Size: {:.2f} MB");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Are you sure you want to reset the play time for '{}' ({})?\n\nYour current play time is {}.\n\nThis action cannot be undone.");
|
TRANSLATE_NOOP("FullscreenUI", "Are you sure you want to reset the play time for '{}' ({})?\n\nYour current play time is {}.\n\nThis action cannot be undone.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Login failed.\nError: {}\n\nPlease check your username and password, and try again.");
|
TRANSLATE_NOOP("FullscreenUI", "Login failed.\nError: {}\n\nPlease check your username and password, and try again.");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State From Backup Slot {}");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State From Slot {}");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Failed to Save State To Slot {}");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Left: ");
|
TRANSLATE_NOOP("FullscreenUI", "Left: ");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Top: ");
|
TRANSLATE_NOOP("FullscreenUI", "Top: ");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Right: ");
|
TRANSLATE_NOOP("FullscreenUI", "Right: ");
|
||||||
@ -9748,13 +9889,14 @@ TRANSLATE_NOOP("FullscreenUI", "AMOLED");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Fit");
|
TRANSLATE_NOOP("FullscreenUI", "Fit");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Fill");
|
TRANSLATE_NOOP("FullscreenUI", "Fill");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Stretch");
|
TRANSLATE_NOOP("FullscreenUI", "Stretch");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Center");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Tile");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Enabled");
|
TRANSLATE_NOOP("FullscreenUI", "Enabled");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Disabled");
|
TRANSLATE_NOOP("FullscreenUI", "Disabled");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Top Left");
|
TRANSLATE_NOOP("FullscreenUI", "Top Left");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Top Center");
|
TRANSLATE_NOOP("FullscreenUI", "Top Center");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Top Right");
|
TRANSLATE_NOOP("FullscreenUI", "Top Right");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Center Left");
|
TRANSLATE_NOOP("FullscreenUI", "Center Left");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Center");
|
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Center Right");
|
TRANSLATE_NOOP("FullscreenUI", "Center Right");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Bottom Left");
|
TRANSLATE_NOOP("FullscreenUI", "Bottom Left");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Bottom Center");
|
TRANSLATE_NOOP("FullscreenUI", "Bottom Center");
|
||||||
@ -9854,9 +9996,9 @@ TRANSLATE_NOOP("FullscreenUI", "Accurate (Recommended)");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Disable Readbacks (Synchronize GS Thread)");
|
TRANSLATE_NOOP("FullscreenUI", "Disable Readbacks (Synchronize GS Thread)");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Unsynchronized (Non-Deterministic)");
|
TRANSLATE_NOOP("FullscreenUI", "Unsynchronized (Non-Deterministic)");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Disabled (Ignore Transfers)");
|
TRANSLATE_NOOP("FullscreenUI", "Disabled (Ignore Transfers)");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Screen Resolution");
|
TRANSLATE_NOOP("FullscreenUI", "Display Resolution (Aspect Corrected)");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Internal Resolution");
|
TRANSLATE_NOOP("FullscreenUI", "Internal Resolution (Aspect Corrected)");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Internal Resolution (Aspect Uncorrected)");
|
TRANSLATE_NOOP("FullscreenUI", "Internal Resolution (No Aspect Correction)");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "PNG");
|
TRANSLATE_NOOP("FullscreenUI", "PNG");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "JPEG");
|
TRANSLATE_NOOP("FullscreenUI", "JPEG");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "WebP");
|
TRANSLATE_NOOP("FullscreenUI", "WebP");
|
||||||
@ -9974,6 +10116,7 @@ TRANSLATE_NOOP("FullscreenUI", "Pause On Start");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Pause On Focus Loss");
|
TRANSLATE_NOOP("FullscreenUI", "Pause On Focus Loss");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Pause On Controller Disconnection");
|
TRANSLATE_NOOP("FullscreenUI", "Pause On Controller Disconnection");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Pause On Menu");
|
TRANSLATE_NOOP("FullscreenUI", "Pause On Menu");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Prompt On State Load/Save Failure");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Confirm Shutdown");
|
TRANSLATE_NOOP("FullscreenUI", "Confirm Shutdown");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Save State On Shutdown");
|
TRANSLATE_NOOP("FullscreenUI", "Save State On Shutdown");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Create Save State Backups");
|
TRANSLATE_NOOP("FullscreenUI", "Create Save State Backups");
|
||||||
@ -9983,6 +10126,7 @@ TRANSLATE_NOOP("FullscreenUI", "Enable Discord Presence");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Start Fullscreen");
|
TRANSLATE_NOOP("FullscreenUI", "Start Fullscreen");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Double-Click Toggles Fullscreen");
|
TRANSLATE_NOOP("FullscreenUI", "Double-Click Toggles Fullscreen");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Hide Cursor In Fullscreen");
|
TRANSLATE_NOOP("FullscreenUI", "Hide Cursor In Fullscreen");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Start Big Picture UI");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "OSD Scale");
|
TRANSLATE_NOOP("FullscreenUI", "OSD Scale");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "OSD Messages Position");
|
TRANSLATE_NOOP("FullscreenUI", "OSD Messages Position");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "OSD Performance Position");
|
TRANSLATE_NOOP("FullscreenUI", "OSD Performance Position");
|
||||||
@ -10037,6 +10181,7 @@ TRANSLATE_NOOP("FullscreenUI", "Integer Upscaling");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Screen Offsets");
|
TRANSLATE_NOOP("FullscreenUI", "Screen Offsets");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Show Overscan");
|
TRANSLATE_NOOP("FullscreenUI", "Show Overscan");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Anti-Blur");
|
TRANSLATE_NOOP("FullscreenUI", "Anti-Blur");
|
||||||
|
TRANSLATE_NOOP("FullscreenUI", "Internal Resolution");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Bilinear Filtering");
|
TRANSLATE_NOOP("FullscreenUI", "Bilinear Filtering");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Trilinear Filtering");
|
TRANSLATE_NOOP("FullscreenUI", "Trilinear Filtering");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Anisotropic Filtering");
|
TRANSLATE_NOOP("FullscreenUI", "Anisotropic Filtering");
|
||||||
@ -10162,7 +10307,6 @@ TRANSLATE_NOOP("FullscreenUI", "Delete Save");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Close Menu");
|
TRANSLATE_NOOP("FullscreenUI", "Close Menu");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Default Boot");
|
TRANSLATE_NOOP("FullscreenUI", "Default Boot");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Delete State");
|
TRANSLATE_NOOP("FullscreenUI", "Delete State");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State");
|
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Full Boot");
|
TRANSLATE_NOOP("FullscreenUI", "Full Boot");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Reset Play Time");
|
TRANSLATE_NOOP("FullscreenUI", "Reset Play Time");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Confirm Reset");
|
TRANSLATE_NOOP("FullscreenUI", "Confirm Reset");
|
||||||
@ -10207,7 +10351,7 @@ TRANSLATE_NOOP("FullscreenUI", "Not Logged In");
|
|||||||
TRANSLATE_NOOP("FullscreenUI", "Game: {0} ({1})");
|
TRANSLATE_NOOP("FullscreenUI", "Game: {0} ({1})");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Rich presence inactive or unsupported.");
|
TRANSLATE_NOOP("FullscreenUI", "Rich presence inactive or unsupported.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Game not loaded or no RetroAchievements available.");
|
TRANSLATE_NOOP("FullscreenUI", "Game not loaded or no RetroAchievements available.");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Card Enabled");
|
TRANSLATE_NOOP("FullscreenUI", "Memory Card Enabled");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Card Name");
|
TRANSLATE_NOOP("FullscreenUI", "Card Name");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Eject Card");
|
TRANSLATE_NOOP("FullscreenUI", "Eject Card");
|
||||||
// TRANSLATION-STRING-AREA-END
|
// TRANSLATION-STRING-AREA-END
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
struct Pcsx2Config;
|
struct Pcsx2Config;
|
||||||
|
|
||||||
@ -26,6 +27,8 @@ namespace FullscreenUI
|
|||||||
void OpenPauseMenu();
|
void OpenPauseMenu();
|
||||||
bool OpenAchievementsWindow();
|
bool OpenAchievementsWindow();
|
||||||
bool OpenLeaderboardsWindow();
|
bool OpenLeaderboardsWindow();
|
||||||
|
void ReportStateLoadError(const std::string& message, std::optional<s32> slot, bool backup);
|
||||||
|
void ReportStateSaveError(const std::string& message, std::optional<s32> slot);
|
||||||
|
|
||||||
// NOTE: Only call from GS thread.
|
// NOTE: Only call from GS thread.
|
||||||
bool IsAchievementsWindowOpen();
|
bool IsAchievementsWindowOpen();
|
||||||
|
|||||||
@ -2396,6 +2396,7 @@ void ImGuiFullscreen::DrawChoiceDialog()
|
|||||||
ImGui::PushStyleColor(ImGuiCol_Text, UIPrimaryTextColor);
|
ImGui::PushStyleColor(ImGuiCol_Text, UIPrimaryTextColor);
|
||||||
ImGui::PushStyleColor(ImGuiCol_TitleBg, UIPrimaryDarkColor);
|
ImGui::PushStyleColor(ImGuiCol_TitleBg, UIPrimaryDarkColor);
|
||||||
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, UIPrimaryColor);
|
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, UIPrimaryColor);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_PopupBg, UIPopupBackgroundColor);
|
||||||
|
|
||||||
const float width = LayoutScale(600.0f);
|
const float width = LayoutScale(600.0f);
|
||||||
const float title_height = g_large_font.second + ImGui::GetStyle().FramePadding.y * 2.0f + ImGui::GetStyle().WindowPadding.y * 2.0f;
|
const float title_height = g_large_font.second + ImGui::GetStyle().FramePadding.y * 2.0f + ImGui::GetStyle().WindowPadding.y * 2.0f;
|
||||||
@ -2464,7 +2465,7 @@ void ImGuiFullscreen::DrawChoiceDialog()
|
|||||||
is_open = false;
|
is_open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PopStyleColor(3);
|
ImGui::PopStyleColor(4);
|
||||||
ImGui::PopStyleVar(3);
|
ImGui::PopStyleVar(3);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
|
|
||||||
@ -2523,7 +2524,7 @@ void ImGuiFullscreen::DrawInputDialog()
|
|||||||
ImGui::PushStyleColor(ImGuiCol_Text, UIPrimaryTextColor);
|
ImGui::PushStyleColor(ImGuiCol_Text, UIPrimaryTextColor);
|
||||||
ImGui::PushStyleColor(ImGuiCol_TitleBg, UIPrimaryDarkColor);
|
ImGui::PushStyleColor(ImGuiCol_TitleBg, UIPrimaryDarkColor);
|
||||||
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, UIPrimaryColor);
|
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, UIPrimaryColor);
|
||||||
ImGui::PushStyleColor(ImGuiCol_PopupBg, UIBackgroundColor);
|
ImGui::PushStyleColor(ImGuiCol_PopupBg, UIPopupBackgroundColor);
|
||||||
|
|
||||||
bool is_open = true;
|
bool is_open = true;
|
||||||
if (ImGui::BeginPopupModal(s_input_dialog_title.c_str(), &is_open,
|
if (ImGui::BeginPopupModal(s_input_dialog_title.c_str(), &is_open,
|
||||||
@ -2715,6 +2716,7 @@ void ImGuiFullscreen::DrawMessageDialog()
|
|||||||
ImGui::PushStyleColor(ImGuiCol_Text, UIPrimaryTextColor);
|
ImGui::PushStyleColor(ImGuiCol_Text, UIPrimaryTextColor);
|
||||||
ImGui::PushStyleColor(ImGuiCol_TitleBg, UIPrimaryDarkColor);
|
ImGui::PushStyleColor(ImGuiCol_TitleBg, UIPrimaryDarkColor);
|
||||||
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, UIPrimaryColor);
|
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, UIPrimaryColor);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_PopupBg, UIPopupBackgroundColor);
|
||||||
|
|
||||||
bool is_open = true;
|
bool is_open = true;
|
||||||
const u32 flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
|
const u32 flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
|
||||||
@ -2745,7 +2747,7 @@ void ImGuiFullscreen::DrawMessageDialog()
|
|||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PopStyleColor(3);
|
ImGui::PopStyleColor(4);
|
||||||
ImGui::PopStyleVar(4);
|
ImGui::PopStyleVar(4);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
|
|
||||||
|
|||||||
@ -1382,8 +1382,7 @@ void SaveStateSelectorUI::LoadCurrentSlot()
|
|||||||
Host::RunOnCPUThread([slot = GetCurrentSlot()]() {
|
Host::RunOnCPUThread([slot = GetCurrentSlot()]() {
|
||||||
Error error;
|
Error error;
|
||||||
if (!VMManager::LoadStateFromSlot(slot, false, &error))
|
if (!VMManager::LoadStateFromSlot(slot, false, &error))
|
||||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
FullscreenUI::ReportStateLoadError(error.GetDescription(), slot, false);
|
||||||
error.GetDescription(), Host::OSD_INFO_DURATION);
|
|
||||||
});
|
});
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
@ -1393,8 +1392,7 @@ void SaveStateSelectorUI::LoadCurrentBackupSlot()
|
|||||||
Host::RunOnCPUThread([slot = GetCurrentSlot()]() {
|
Host::RunOnCPUThread([slot = GetCurrentSlot()]() {
|
||||||
Error error;
|
Error error;
|
||||||
if (!VMManager::LoadStateFromSlot(slot, true, &error))
|
if (!VMManager::LoadStateFromSlot(slot, true, &error))
|
||||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
FullscreenUI::ReportStateLoadError(error.GetDescription(), slot, true);
|
||||||
error.GetDescription(), Host::OSD_INFO_DURATION);
|
|
||||||
});
|
});
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
@ -1402,7 +1400,9 @@ void SaveStateSelectorUI::LoadCurrentBackupSlot()
|
|||||||
void SaveStateSelectorUI::SaveCurrentSlot()
|
void SaveStateSelectorUI::SaveCurrentSlot()
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([slot = GetCurrentSlot()]() {
|
Host::RunOnCPUThread([slot = GetCurrentSlot()]() {
|
||||||
VMManager::SaveStateToSlot(slot);
|
VMManager::SaveStateToSlot(slot, true, [slot](const std::string& error) {
|
||||||
|
FullscreenUI::ReportStateSaveError(error, slot);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -765,9 +765,9 @@ std::optional<InputBindingKey> SDLInputSource::ParseKeyString(const std::string_
|
|||||||
{
|
{
|
||||||
shown_prompt = true;
|
shown_prompt = true;
|
||||||
Host::ReportInfoAsync(TRANSLATE("SDLInputSource", "SDL3 Migration"),
|
Host::ReportInfoAsync(TRANSLATE("SDLInputSource", "SDL3 Migration"),
|
||||||
TRANSLATE("SDLInputSource", "As part of our upgrade to SDL3, we've had to migrate your binds\n"
|
TRANSLATE("SDLInputSource", "As part of our upgrade to SDL3, we've had to migrate your binds.\n"
|
||||||
"Your controller did not match the Xbox layout and may need rebinding\n"
|
"Your controller did not match the Xbox layout and may need rebinding.\n"
|
||||||
"Please verify your controller settings and amend if required"));
|
"Please verify your controller settings and amend if required."));
|
||||||
|
|
||||||
// Also apply BPM setting for legacy binds
|
// Also apply BPM setting for legacy binds
|
||||||
// We assume this is a Nintendo controller, BPM will check if it is
|
// We assume this is a Nintendo controller, BPM will check if it is
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "Host.h"
|
#include "Host.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "Elfheader.h"
|
#include "Elfheader.h"
|
||||||
|
#include "SaveState.h"
|
||||||
#include "PINE.h"
|
#include "PINE.h"
|
||||||
#include "VMManager.h"
|
#include "VMManager.h"
|
||||||
#include "common/Error.h"
|
#include "common/Error.h"
|
||||||
@ -19,7 +20,6 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "IconsFontAwesome6.h"
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define read_portable(a, b, c) (recv(a, (char*)b, c, 0))
|
#define read_portable(a, b, c) (recv(a, (char*)b, c, 0))
|
||||||
@ -646,7 +646,11 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
|
|||||||
goto error;
|
goto error;
|
||||||
if (!SafetyChecks(buf_cnt, 1, ret_cnt, 0, buf_size)) [[unlikely]]
|
if (!SafetyChecks(buf_cnt, 1, ret_cnt, 0, buf_size)) [[unlikely]]
|
||||||
goto error;
|
goto error;
|
||||||
Host::RunOnCPUThread([slot = FromSpan<u8>(buf, buf_cnt)] { VMManager::SaveStateToSlot(slot); });
|
Host::RunOnCPUThread([slot = FromSpan<u8>(buf, buf_cnt)] {
|
||||||
|
VMManager::SaveStateToSlot(slot, true, [slot](const std::string& error) {
|
||||||
|
SaveState_ReportSaveErrorOSD(error, slot);
|
||||||
|
});
|
||||||
|
});
|
||||||
buf_cnt += 1;
|
buf_cnt += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -659,8 +663,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
|
|||||||
Host::RunOnCPUThread([slot = FromSpan<u8>(buf, buf_cnt)] {
|
Host::RunOnCPUThread([slot = FromSpan<u8>(buf, buf_cnt)] {
|
||||||
Error state_error;
|
Error state_error;
|
||||||
if (!VMManager::LoadStateFromSlot(slot, false, &state_error))
|
if (!VMManager::LoadStateFromSlot(slot, false, &state_error))
|
||||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
SaveState_ReportLoadErrorOSD(state_error.GetDescription(), slot, false);
|
||||||
state_error.GetDescription(), Host::OSD_INFO_DURATION);
|
|
||||||
});
|
});
|
||||||
buf_cnt += 1;
|
buf_cnt += 1;
|
||||||
break;
|
break;
|
||||||
|
|||||||
187
pcsx2/Patch.cpp
187
pcsx2/Patch.cpp
@ -51,7 +51,7 @@ namespace Patch
|
|||||||
BYTES_T
|
BYTES_T
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr std::array<const char*, 3> s_place_to_string = {{"0", "1", "2"}};
|
static constexpr std::array<const char*, 4> s_place_to_string = {{"0", "1", "2", "3"}};
|
||||||
static constexpr std::array<const char*, 2> s_cpu_to_string = {{"EE", "IOP"}};
|
static constexpr std::array<const char*, 2> s_cpu_to_string = {{"EE", "IOP"}};
|
||||||
static constexpr std::array<const char*, 9> s_type_to_string = {
|
static constexpr std::array<const char*, 9> s_type_to_string = {
|
||||||
{"byte", "short", "word", "double", "extended", "beshort", "beword", "bedouble", "bytes"}};
|
{"byte", "short", "word", "double", "extended", "beshort", "beword", "bedouble", "bytes"}};
|
||||||
@ -125,10 +125,6 @@ namespace Patch
|
|||||||
void (*func)(PatchGroup* group, const std::string_view cmd, const std::string_view param);
|
void (*func)(PatchGroup* group, const std::string_view cmd, const std::string_view param);
|
||||||
};
|
};
|
||||||
|
|
||||||
using PatchList = std::vector<PatchGroup>;
|
|
||||||
using ActivePatchList = std::vector<const PatchCommand*>;
|
|
||||||
using EnablePatchList = std::vector<std::string>;
|
|
||||||
|
|
||||||
namespace PatchFunc
|
namespace PatchFunc
|
||||||
{
|
{
|
||||||
static void patch(PatchGroup* group, const std::string_view cmd, const std::string_view param);
|
static void patch(PatchGroup* group, const std::string_view cmd, const std::string_view param);
|
||||||
@ -141,23 +137,23 @@ namespace Patch
|
|||||||
static int PatchTableExecute(PatchGroup* group, const std::string_view lhs, const std::string_view rhs,
|
static int PatchTableExecute(PatchGroup* group, const std::string_view lhs, const std::string_view rhs,
|
||||||
const std::span<const PatchTextTable>& Table);
|
const std::span<const PatchTextTable>& Table);
|
||||||
static void LoadPatchLine(PatchGroup* group, const std::string_view line);
|
static void LoadPatchLine(PatchGroup* group, const std::string_view line);
|
||||||
static u32 LoadPatchesFromString(PatchList* patch_list, const std::string& patch_file);
|
static u32 LoadPatchesFromString(std::vector<PatchGroup>* patch_list, const std::string& patch_file);
|
||||||
static bool OpenPatchesZip();
|
static bool OpenPatchesZip();
|
||||||
static std::string GetPnachTemplate(
|
static std::string GetPnachTemplate(
|
||||||
const std::string_view serial, u32 crc, bool include_serial, bool add_wildcard, bool all_crcs);
|
const std::string_view serial, u32 crc, bool include_serial, bool add_wildcard, bool all_crcs);
|
||||||
static std::vector<std::string> FindPatchFilesOnDisk(
|
static std::vector<std::string> FindPatchFilesOnDisk(
|
||||||
const std::string_view serial, u32 crc, bool cheats, bool all_crcs);
|
const std::string_view serial, u32 crc, bool cheats, bool all_crcs);
|
||||||
|
|
||||||
static bool ContainsPatchName(const PatchInfoList& patches, const std::string_view patchName);
|
static bool ContainsPatchName(const std::vector<PatchInfo>& patches, const std::string_view patchName);
|
||||||
static bool ContainsPatchName(const PatchList& patches, const std::string_view patchName);
|
static bool ContainsPatchName(const std::vector<PatchGroup>& patches, const std::string_view patchName);
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
static void EnumeratePnachFiles(const std::string_view serial, u32 crc, bool cheats, bool for_ui, const F& f);
|
static void EnumeratePnachFiles(const std::string_view serial, u32 crc, bool cheats, bool for_ui, const F& f);
|
||||||
|
|
||||||
static bool PatchStringHasUnlabelledPatch(const std::string& pnach_data);
|
static bool PatchStringHasUnlabelledPatch(const std::string& pnach_data);
|
||||||
static void ExtractPatchInfo(PatchInfoList* dst, const std::string& pnach_data, u32* num_unlabelled_patches);
|
static void ExtractPatchInfo(std::vector<PatchInfo>* dst, const std::string& pnach_data, u32* num_unlabelled_patches);
|
||||||
static void ReloadEnabledLists();
|
static void ReloadEnabledLists();
|
||||||
static u32 EnablePatches(const PatchList& patches, const EnablePatchList& enable_list, const EnablePatchList& enable_immediately_list);
|
static u32 EnablePatches(const std::vector<PatchGroup>* patches, const std::vector<std::string>& enable_list, const std::vector<std::string>* enable_immediately_list);
|
||||||
|
|
||||||
static void ApplyPatch(const PatchCommand* p);
|
static void ApplyPatch(const PatchCommand* p);
|
||||||
static void ApplyDynaPatch(const DynamicPatch& patch, u32 address);
|
static void ApplyDynaPatch(const DynamicPatch& patch, u32 address);
|
||||||
@ -175,21 +171,21 @@ namespace Patch
|
|||||||
const char* PATCH_DISABLE_CONFIG_KEY = "Disable";
|
const char* PATCH_DISABLE_CONFIG_KEY = "Disable";
|
||||||
|
|
||||||
static zip_t* s_patches_zip;
|
static zip_t* s_patches_zip;
|
||||||
static PatchList s_gamedb_patches;
|
static std::vector<PatchGroup> s_gamedb_patches;
|
||||||
static PatchList s_game_patches;
|
static std::vector<PatchGroup> s_game_patches;
|
||||||
static PatchList s_cheat_patches;
|
static std::vector<PatchGroup> s_cheat_patches;
|
||||||
|
|
||||||
static u32 s_gamedb_counts = 0;
|
static u32 s_gamedb_counts = 0;
|
||||||
static u32 s_patches_counts = 0;
|
static u32 s_patches_counts = 0;
|
||||||
static u32 s_cheats_counts = 0;
|
static u32 s_cheats_counts = 0;
|
||||||
|
|
||||||
static ActivePatchList s_active_patches;
|
static std::vector<const PatchCommand*> s_active_patches;
|
||||||
static std::vector<DynamicPatch> s_active_gamedb_dynamic_patches;
|
static std::vector<DynamicPatch> s_active_gamedb_dynamic_patches;
|
||||||
static std::vector<DynamicPatch> s_active_pnach_dynamic_patches;
|
static std::vector<DynamicPatch> s_active_pnach_dynamic_patches;
|
||||||
static EnablePatchList s_enabled_cheats;
|
static std::vector<std::string> s_enabled_cheats;
|
||||||
static EnablePatchList s_enabled_patches;
|
static std::vector<std::string> s_enabled_patches;
|
||||||
static EnablePatchList s_just_enabled_cheats;
|
static std::vector<std::string> s_just_enabled_cheats;
|
||||||
static EnablePatchList s_just_enabled_patches;
|
static std::vector<std::string> s_just_enabled_patches;
|
||||||
static u32 s_patches_crc;
|
static u32 s_patches_crc;
|
||||||
static std::optional<float> s_override_aspect_ratio;
|
static std::optional<float> s_override_aspect_ratio;
|
||||||
static std::optional<GSInterlaceMode> s_override_interlace_mode;
|
static std::optional<GSInterlaceMode> s_override_interlace_mode;
|
||||||
@ -218,7 +214,7 @@ void Patch::TrimPatchLine(std::string& buffer)
|
|||||||
buffer.erase(pos);
|
buffer.erase(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Patch::ContainsPatchName(const PatchList& patch_list, const std::string_view patch_name)
|
bool Patch::ContainsPatchName(const std::vector<PatchGroup>& patch_list, const std::string_view patch_name)
|
||||||
{
|
{
|
||||||
return std::find_if(patch_list.begin(), patch_list.end(), [&patch_name](const PatchGroup& patch) {
|
return std::find_if(patch_list.begin(), patch_list.end(), [&patch_name](const PatchGroup& patch) {
|
||||||
return patch.name == patch_name;
|
return patch.name == patch_name;
|
||||||
@ -253,7 +249,7 @@ void Patch::LoadPatchLine(PatchGroup* group, const std::string_view line)
|
|||||||
PatchTableExecute(group, key, value, s_patch_commands);
|
PatchTableExecute(group, key, value, s_patch_commands);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Patch::LoadPatchesFromString(PatchList* patch_list, const std::string& patch_file)
|
u32 Patch::LoadPatchesFromString(std::vector<PatchGroup>* patch_list, const std::string& patch_file)
|
||||||
{
|
{
|
||||||
const size_t before = patch_list->size();
|
const size_t before = patch_list->size();
|
||||||
|
|
||||||
@ -264,7 +260,7 @@ u32 Patch::LoadPatchesFromString(PatchList* patch_list, const std::string& patch
|
|||||||
// Ungrouped/legacy patches should merge with other ungrouped patches.
|
// Ungrouped/legacy patches should merge with other ungrouped patches.
|
||||||
if (current_patch_group.name.empty())
|
if (current_patch_group.name.empty())
|
||||||
{
|
{
|
||||||
const PatchList::iterator ungrouped_patch = std::find_if(patch_list->begin(), patch_list->end(),
|
const std::vector<PatchGroup>::iterator ungrouped_patch = std::find_if(patch_list->begin(), patch_list->end(),
|
||||||
[](const PatchGroup& pg) { return pg.name.empty(); });
|
[](const PatchGroup& pg) { return pg.name.empty(); });
|
||||||
if (ungrouped_patch != patch_list->end())
|
if (ungrouped_patch != patch_list->end())
|
||||||
{
|
{
|
||||||
@ -407,7 +403,7 @@ std::vector<std::string> Patch::FindPatchFilesOnDisk(const std::string_view seri
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Patch::ContainsPatchName(const PatchInfoList& patches, const std::string_view patchName)
|
bool Patch::ContainsPatchName(const std::vector<PatchInfo>& patches, const std::string_view patchName)
|
||||||
{
|
{
|
||||||
return std::find_if(patches.begin(), patches.end(), [&patchName](const PatchInfo& patch) {
|
return std::find_if(patches.begin(), patches.end(), [&patchName](const PatchInfo& patch) {
|
||||||
return patch.name == patchName;
|
return patch.name == patchName;
|
||||||
@ -491,11 +487,15 @@ bool Patch::PatchStringHasUnlabelledPatch(const std::string& pnach_data)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Patch::ExtractPatchInfo(PatchInfoList* dst, const std::string& pnach_data, u32* num_unlabelled_patches)
|
void Patch::ExtractPatchInfo(std::vector<PatchInfo>* dst, const std::string& pnach_data, u32* num_unlabelled_patches)
|
||||||
{
|
{
|
||||||
std::istringstream ss(pnach_data);
|
std::istringstream ss(pnach_data);
|
||||||
std::string line;
|
std::string line;
|
||||||
PatchInfo current_patch;
|
PatchInfo current_patch;
|
||||||
|
|
||||||
|
std::optional<patch_place_type> last_place;
|
||||||
|
bool unknown_place = false;
|
||||||
|
|
||||||
while (std::getline(ss, line))
|
while (std::getline(ss, line))
|
||||||
{
|
{
|
||||||
TrimPatchLine(line);
|
TrimPatchLine(line);
|
||||||
@ -522,6 +522,8 @@ void Patch::ExtractPatchInfo(PatchInfoList* dst, const std::string& pnach_data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
current_patch = {};
|
current_patch = {};
|
||||||
|
last_place = std::nullopt;
|
||||||
|
unknown_place = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_patch.name = line.substr(1, line.length() - 2);
|
current_patch.name = line.substr(1, line.length() - 2);
|
||||||
@ -534,13 +536,52 @@ void Patch::ExtractPatchInfo(PatchInfoList* dst, const std::string& pnach_data,
|
|||||||
// Just ignore other directives, who knows what rubbish people have in here.
|
// Just ignore other directives, who knows what rubbish people have in here.
|
||||||
// Use comment for description if it hasn't been otherwise specified.
|
// Use comment for description if it hasn't been otherwise specified.
|
||||||
if (key == "author")
|
if (key == "author")
|
||||||
|
{
|
||||||
current_patch.author = value;
|
current_patch.author = value;
|
||||||
|
}
|
||||||
else if (key == "description")
|
else if (key == "description")
|
||||||
|
{
|
||||||
current_patch.description = value;
|
current_patch.description = value;
|
||||||
|
}
|
||||||
else if (key == "comment" && current_patch.description.empty())
|
else if (key == "comment" && current_patch.description.empty())
|
||||||
|
{
|
||||||
current_patch.description = value;
|
current_patch.description = value;
|
||||||
else if (key == "patch" && !has_patch && num_unlabelled_patches)
|
}
|
||||||
(*num_unlabelled_patches)++;
|
else if (key == "patch")
|
||||||
|
{
|
||||||
|
if (!has_patch && num_unlabelled_patches)
|
||||||
|
(*num_unlabelled_patches)++;
|
||||||
|
|
||||||
|
// Try to extract the place value of the patch lines so we can
|
||||||
|
// display it in the GUI if they all match. TODO: Don't duplicate
|
||||||
|
// all this parsing logic twice.
|
||||||
|
if (unknown_place)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string::size_type comma_pos = value.find(",");
|
||||||
|
if (comma_pos == std::string::npos)
|
||||||
|
comma_pos = 0;
|
||||||
|
const std::string_view padded_place = value.substr(0, comma_pos);
|
||||||
|
const std::string_view place_string = StringUtil::StripWhitespace(padded_place);
|
||||||
|
const std::optional<patch_place_type> place = LookupEnumName<patch_place_type>(
|
||||||
|
place_string, s_place_to_string);
|
||||||
|
if (!place.has_value() || (last_place.has_value() && place != last_place))
|
||||||
|
{
|
||||||
|
// This group contains patch lines with different or invalid
|
||||||
|
// place values.
|
||||||
|
current_patch.place = std::nullopt;
|
||||||
|
unknown_place = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_patch.place = place;
|
||||||
|
last_place = place;
|
||||||
|
}
|
||||||
|
else if (key == "dpatch")
|
||||||
|
{
|
||||||
|
current_patch.place = std::nullopt;
|
||||||
|
unknown_place = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last one.
|
// Last one.
|
||||||
@ -570,9 +611,9 @@ std::string_view Patch::PatchInfo::GetNameParentPart() const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Patch::PatchInfoList Patch::GetPatchInfo(const std::string_view serial, u32 crc, bool cheats, bool showAllCRCS, u32* num_unlabelled_patches)
|
std::vector<Patch::PatchInfo> Patch::GetPatchInfo(const std::string_view serial, u32 crc, bool cheats, bool showAllCRCS, u32* num_unlabelled_patches)
|
||||||
{
|
{
|
||||||
PatchInfoList ret;
|
std::vector<PatchInfo> ret;
|
||||||
|
|
||||||
if (num_unlabelled_patches)
|
if (num_unlabelled_patches)
|
||||||
*num_unlabelled_patches = 0;
|
*num_unlabelled_patches = 0;
|
||||||
@ -592,14 +633,14 @@ std::string Patch::GetPnachFilename(const std::string_view serial, u32 crc, bool
|
|||||||
|
|
||||||
void Patch::ReloadEnabledLists()
|
void Patch::ReloadEnabledLists()
|
||||||
{
|
{
|
||||||
const EnablePatchList prev_enabled_cheats = std::move(s_enabled_cheats);
|
const std::vector<std::string> prev_enabled_cheats = std::move(s_enabled_cheats);
|
||||||
if (EmuConfig.EnableCheats && !Achievements::IsHardcoreModeActive())
|
if (EmuConfig.EnableCheats && !Achievements::IsHardcoreModeActive())
|
||||||
s_enabled_cheats = Host::GetStringListSetting(CHEATS_CONFIG_SECTION, PATCH_ENABLE_CONFIG_KEY);
|
s_enabled_cheats = Host::GetStringListSetting(CHEATS_CONFIG_SECTION, PATCH_ENABLE_CONFIG_KEY);
|
||||||
else
|
else
|
||||||
s_enabled_cheats = {};
|
s_enabled_cheats = {};
|
||||||
|
|
||||||
const EnablePatchList prev_enabled_patches = std::exchange(s_enabled_patches, Host::GetStringListSetting(PATCHES_CONFIG_SECTION, PATCH_ENABLE_CONFIG_KEY));
|
const std::vector<std::string> prev_enabled_patches = std::exchange(s_enabled_patches, Host::GetStringListSetting(PATCHES_CONFIG_SECTION, PATCH_ENABLE_CONFIG_KEY));
|
||||||
const EnablePatchList disabled_patches = Host::GetStringListSetting(PATCHES_CONFIG_SECTION, PATCH_DISABLE_CONFIG_KEY);
|
const std::vector<std::string> disabled_patches = Host::GetStringListSetting(PATCHES_CONFIG_SECTION, PATCH_DISABLE_CONFIG_KEY);
|
||||||
|
|
||||||
// Name based matching for widescreen/NI settings.
|
// Name based matching for widescreen/NI settings.
|
||||||
if (EmuConfig.EnableWideScreenPatches)
|
if (EmuConfig.EnableWideScreenPatches)
|
||||||
@ -649,12 +690,10 @@ void Patch::ReloadEnabledLists()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Patch::EnablePatches(const PatchList& patches, const EnablePatchList& enable_list, const EnablePatchList& enable_immediately_list)
|
u32 Patch::EnablePatches(const std::vector<PatchGroup>* patches, const std::vector<std::string>& enable_list, const std::vector<std::string>* enable_immediately_list)
|
||||||
{
|
{
|
||||||
ActivePatchList patches_to_apply_immediately;
|
|
||||||
|
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
for (const PatchGroup& p : patches)
|
for (const PatchGroup& p : *patches)
|
||||||
{
|
{
|
||||||
// For compatibility, we auto enable anything that's not labelled.
|
// For compatibility, we auto enable anything that's not labelled.
|
||||||
// Also for gamedb patches.
|
// Also for gamedb patches.
|
||||||
@ -664,7 +703,6 @@ u32 Patch::EnablePatches(const PatchList& patches, const EnablePatchList& enable
|
|||||||
Console.WriteLn(Color_Green, fmt::format("Enabled patch: {}",
|
Console.WriteLn(Color_Green, fmt::format("Enabled patch: {}",
|
||||||
p.name.empty() ? std::string_view("<unknown>") : std::string_view(p.name)));
|
p.name.empty() ? std::string_view("<unknown>") : std::string_view(p.name)));
|
||||||
|
|
||||||
const bool apply_immediately = std::find(enable_immediately_list.begin(), enable_immediately_list.end(), p.name) != enable_immediately_list.end();
|
|
||||||
for (const PatchCommand& ip : p.patches)
|
for (const PatchCommand& ip : p.patches)
|
||||||
{
|
{
|
||||||
// print the actual patch lines only in verbose mode (even in devel)
|
// print the actual patch lines only in verbose mode (even in devel)
|
||||||
@ -672,8 +710,6 @@ u32 Patch::EnablePatches(const PatchList& patches, const EnablePatchList& enable
|
|||||||
DevCon.WriteLnFmt(" {}", ip.ToString());
|
DevCon.WriteLnFmt(" {}", ip.ToString());
|
||||||
|
|
||||||
s_active_patches.push_back(&ip);
|
s_active_patches.push_back(&ip);
|
||||||
if (apply_immediately && ip.placetopatch == PPT_ONCE_ON_LOAD)
|
|
||||||
patches_to_apply_immediately.push_back(&ip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const DynamicPatch& dp : p.dpatches)
|
for (const DynamicPatch& dp : p.dpatches)
|
||||||
@ -690,12 +726,28 @@ u32 Patch::EnablePatches(const PatchList& patches, const EnablePatchList& enable
|
|||||||
count += p.name.empty() ? (static_cast<u32>(p.patches.size()) + static_cast<u32>(p.dpatches.size())) : 1;
|
count += p.name.empty() ? (static_cast<u32>(p.patches.size()) + static_cast<u32>(p.dpatches.size())) : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!patches_to_apply_immediately.empty())
|
// Apply PPT_ON_LOAD_OR_WHEN_ENABLED patches immediately.
|
||||||
|
if (enable_immediately_list && !enable_immediately_list->empty())
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([patches = std::move(patches_to_apply_immediately)]() {
|
// Don't pass pointers to patch objects themselves here just in case the
|
||||||
for (const PatchCommand* i : patches)
|
// patches are reloaded twice in a row before this event makes it.
|
||||||
|
Host::RunOnCPUThread([patches, enable_immediately_list]() {
|
||||||
|
for (const PatchGroup& group : *patches)
|
||||||
{
|
{
|
||||||
ApplyPatch(i);
|
const bool apply_immediately = std::find(
|
||||||
|
enable_immediately_list->begin(),
|
||||||
|
enable_immediately_list->end(),
|
||||||
|
group.name) != enable_immediately_list->end();
|
||||||
|
if (!apply_immediately)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (const PatchCommand& command : group.patches)
|
||||||
|
{
|
||||||
|
if (command.placetopatch != PPT_ON_LOAD_OR_WHEN_ENABLED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ApplyPatch(&command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -762,19 +814,23 @@ void Patch::UpdateActivePatches(bool reload_enabled_list, bool verbose, bool ver
|
|||||||
u32 gp_count = 0;
|
u32 gp_count = 0;
|
||||||
if (EmuConfig.EnablePatches)
|
if (EmuConfig.EnablePatches)
|
||||||
{
|
{
|
||||||
gp_count = EnablePatches(s_gamedb_patches, EnablePatchList(), EnablePatchList());
|
gp_count = EnablePatches(&s_gamedb_patches, std::vector<std::string>(), nullptr);
|
||||||
s_gamedb_counts = gp_count;
|
s_gamedb_counts = gp_count;
|
||||||
if (gp_count > 0)
|
if (gp_count > 0)
|
||||||
message.append(TRANSLATE_PLURAL_STR("Patch", "%n GameDB patches are active.", "OSD Message", gp_count));
|
message.append(TRANSLATE_PLURAL_STR("Patch", "%n GameDB patches are active.", "OSD Message", gp_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 p_count = EnablePatches(s_game_patches, s_enabled_patches, apply_new_patches ? s_just_enabled_patches : EnablePatchList());
|
const u32 p_count = EnablePatches(
|
||||||
|
&s_game_patches, s_enabled_patches, apply_new_patches ? &s_just_enabled_patches : nullptr);
|
||||||
s_patches_counts = p_count;
|
s_patches_counts = p_count;
|
||||||
if (p_count > 0)
|
if (p_count > 0)
|
||||||
message.append_format("{}{}", message.empty() ? "" : "\n",
|
message.append_format("{}{}", message.empty() ? "" : "\n",
|
||||||
TRANSLATE_PLURAL_STR("Patch", "%n game patches are active.", "OSD Message", p_count));
|
TRANSLATE_PLURAL_STR("Patch", "%n game patches are active.", "OSD Message", p_count));
|
||||||
|
|
||||||
const u32 c_count = EmuConfig.EnableCheats ? EnablePatches(s_cheat_patches, s_enabled_cheats, apply_new_patches ? s_just_enabled_cheats : EnablePatchList()) : 0;
|
u32 c_count = 0;
|
||||||
|
if (EmuConfig.EnableCheats)
|
||||||
|
c_count = EnablePatches(
|
||||||
|
&s_cheat_patches, s_enabled_cheats, apply_new_patches ? &s_just_enabled_cheats : nullptr);
|
||||||
s_cheats_counts = c_count;
|
s_cheats_counts = c_count;
|
||||||
if (c_count > 0)
|
if (c_count > 0)
|
||||||
message.append_format("{}{}", message.empty() ? "" : "\n",
|
message.append_format("{}{}", message.empty() ? "" : "\n",
|
||||||
@ -892,7 +948,7 @@ void Patch::PatchFunc::patch(PatchGroup* group, const std::string_view cmd, cons
|
|||||||
|
|
||||||
if (!placetopatch.has_value())
|
if (!placetopatch.has_value())
|
||||||
{
|
{
|
||||||
PATCH_ERROR("Invalid 'place' value '{}' (0 - once on startup, 1: continuously)", pieces[0]);
|
PATCH_ERROR("Invalid 'place' value '{}' (0: on boot only, 1: continuously, 2: on boot and continuously, 3: on boot and when enabled in the GUI)", pieces[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!addr.has_value() || !addr_end.empty())
|
if (!addr.has_value() || !addr_end.empty())
|
||||||
@ -1083,6 +1139,19 @@ void Patch::PatchFunc::dpatch(PatchGroup* group, const std::string_view cmd, con
|
|||||||
group->dpatches.push_back(dpatch);
|
group->dpatches.push_back(dpatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Patch::ApplyBootPatches()
|
||||||
|
{
|
||||||
|
ApplyLoadedPatches(PPT_ONCE_ON_LOAD);
|
||||||
|
ApplyLoadedPatches(PPT_COMBINED_0_1);
|
||||||
|
ApplyLoadedPatches(PPT_ON_LOAD_OR_WHEN_ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Patch::ApplyVsyncPatches()
|
||||||
|
{
|
||||||
|
ApplyLoadedPatches(PPT_CONTINUOUSLY);
|
||||||
|
ApplyLoadedPatches(PPT_COMBINED_0_1);
|
||||||
|
}
|
||||||
|
|
||||||
// This is for applying patches directly to memory
|
// This is for applying patches directly to memory
|
||||||
void Patch::ApplyLoadedPatches(patch_place_type place)
|
void Patch::ApplyLoadedPatches(patch_place_type place)
|
||||||
{
|
{
|
||||||
@ -1731,3 +1800,31 @@ void Patch::ApplyDynaPatch(const DynamicPatch& patch, u32 address)
|
|||||||
memWrite32(address + replacement.offset, replacement.value);
|
memWrite32(address + replacement.offset, replacement.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* Patch::PlaceToString(std::optional<patch_place_type> place)
|
||||||
|
{
|
||||||
|
if (!place.has_value())
|
||||||
|
//: Time when a patch is applied.
|
||||||
|
return TRANSLATE("Patch", "Unknown");
|
||||||
|
|
||||||
|
switch (*place)
|
||||||
|
{
|
||||||
|
case Patch::PPT_ONCE_ON_LOAD:
|
||||||
|
//: Time when a patch is applied.
|
||||||
|
return TRANSLATE("Patch", "Only On Startup");
|
||||||
|
case Patch::PPT_CONTINUOUSLY:
|
||||||
|
//: Time when a patch is applied.
|
||||||
|
return TRANSLATE("Patch", "Every Frame");
|
||||||
|
case Patch::PPT_COMBINED_0_1:
|
||||||
|
//: Time when a patch is applied.
|
||||||
|
return TRANSLATE("Patch", "On Startup & Every Frame");
|
||||||
|
case Patch::PPT_ON_LOAD_OR_WHEN_ENABLED:
|
||||||
|
//: Time when a patch is applied.
|
||||||
|
return TRANSLATE("Patch", "On Startup & When Enabled");
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|||||||
@ -29,23 +29,22 @@ namespace Patch
|
|||||||
// In PCSX2 it indicates how/when/where the patch line should be applied. If
|
// In PCSX2 it indicates how/when/where the patch line should be applied. If
|
||||||
// place is not one of the supported values then the patch line is never applied.
|
// place is not one of the supported values then the patch line is never applied.
|
||||||
// PCSX2 currently supports the following values:
|
// PCSX2 currently supports the following values:
|
||||||
// 0 - apply the patch line once on game boot/startup
|
// 0 - apply the patch line once on game boot only
|
||||||
// 1 - apply the patch line continuously (technically - on every vsync)
|
// 1 - apply the patch line continuously (technically - on every vsync)
|
||||||
// 2 - effect of 0 and 1 combined, see below
|
// 2 - effect of 0 and 1 combined, see below
|
||||||
|
// 3 - apply the patch line once on game boot or when enabled in the GUI
|
||||||
// Note:
|
// Note:
|
||||||
// - while it may seem that a value of 1 does the same as 0, but also later
|
// - while it may seem that a value of 1 does the same as 0, but also later
|
||||||
// continues to apply the patch on every vsync - it's not.
|
// continues to apply the patch on every vsync - it's not.
|
||||||
// The current (and past) behavior is that these patches are applied at different
|
// The current (and past) behavior is that these patches are applied at different
|
||||||
// places at the code, and it's possible, depending on circumstances, that 0 patches
|
// places at the code, and it's possible, depending on circumstances, that 0 patches
|
||||||
// will get applied before the first vsync and therefore earlier than 1 patches.
|
// will get applied before the first vsync and therefore earlier than 1 patches.
|
||||||
// - There's no "place" value which indicates to apply both once on startup
|
|
||||||
// and then also continuously, however such behavior can be achieved by
|
|
||||||
// duplicating the line where one has a 0 place and the other has a 1 place.
|
|
||||||
enum patch_place_type : u8
|
enum patch_place_type : u8
|
||||||
{
|
{
|
||||||
PPT_ONCE_ON_LOAD = 0,
|
PPT_ONCE_ON_LOAD = 0,
|
||||||
PPT_CONTINUOUSLY = 1,
|
PPT_CONTINUOUSLY = 1,
|
||||||
PPT_COMBINED_0_1 = 2,
|
PPT_COMBINED_0_1 = 2,
|
||||||
|
PPT_ON_LOAD_OR_WHEN_ENABLED = 3,
|
||||||
|
|
||||||
PPT_END_MARKER
|
PPT_END_MARKER
|
||||||
};
|
};
|
||||||
@ -56,12 +55,14 @@ namespace Patch
|
|||||||
std::string description;
|
std::string description;
|
||||||
std::string author;
|
std::string author;
|
||||||
|
|
||||||
|
// This is only populated if all the patch lines in a given group have
|
||||||
|
// the same place value.
|
||||||
|
std::optional<patch_place_type> place;
|
||||||
|
|
||||||
std::string_view GetNamePart() const;
|
std::string_view GetNamePart() const;
|
||||||
std::string_view GetNameParentPart() const;
|
std::string_view GetNameParentPart() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
using PatchInfoList = std::vector<PatchInfo>;
|
|
||||||
|
|
||||||
struct DynamicPatchEntry
|
struct DynamicPatchEntry
|
||||||
{
|
{
|
||||||
u32 offset;
|
u32 offset;
|
||||||
@ -80,7 +81,7 @@ namespace Patch
|
|||||||
extern const char* PATCH_ENABLE_CONFIG_KEY;
|
extern const char* PATCH_ENABLE_CONFIG_KEY;
|
||||||
extern const char* PATCH_DISABLE_CONFIG_KEY;
|
extern const char* PATCH_DISABLE_CONFIG_KEY;
|
||||||
|
|
||||||
extern PatchInfoList GetPatchInfo(const std::string_view serial, u32 crc, bool cheats, bool showAllCRCS, u32* num_unlabelled_patches);
|
extern std::vector<PatchInfo> GetPatchInfo(const std::string_view serial, u32 crc, bool cheats, bool showAllCRCS, u32* num_unlabelled_patches);
|
||||||
|
|
||||||
/// Returns the path to a new cheat/patch pnach for the specified serial and CRC.
|
/// Returns the path to a new cheat/patch pnach for the specified serial and CRC.
|
||||||
extern std::string GetPnachFilename(const std::string_view serial, u32 crc, bool cheats);
|
extern std::string GetPnachFilename(const std::string_view serial, u32 crc, bool cheats);
|
||||||
@ -97,6 +98,13 @@ namespace Patch
|
|||||||
extern void LoadDynamicPatches(const std::vector<DynamicPatch>& patches);
|
extern void LoadDynamicPatches(const std::vector<DynamicPatch>& patches);
|
||||||
extern void ApplyDynamicPatches(u32 pc);
|
extern void ApplyDynamicPatches(u32 pc);
|
||||||
|
|
||||||
|
// Apply all loaded patches that should be applied when the entry point is
|
||||||
|
// being recompiled.
|
||||||
|
extern void ApplyBootPatches();
|
||||||
|
|
||||||
|
// Apply all loaded patches that should be applied during vsync.
|
||||||
|
extern void ApplyVsyncPatches();
|
||||||
|
|
||||||
// Patches the emulation memory by applying all the loaded patches with a specific place value.
|
// Patches the emulation memory by applying all the loaded patches with a specific place value.
|
||||||
// Note: unless you know better, there's no need to check whether or not different patch sources
|
// Note: unless you know better, there's no need to check whether or not different patch sources
|
||||||
// are enabled (e.g. ws patches, auto game fixes, etc) before calling ApplyLoadedPatches,
|
// are enabled (e.g. ws patches, auto game fixes, etc) before calling ApplyLoadedPatches,
|
||||||
@ -112,4 +120,6 @@ namespace Patch
|
|||||||
extern u32 GetAllActivePatchesCount();
|
extern u32 GetAllActivePatchesCount();
|
||||||
|
|
||||||
extern bool IsGloballyToggleablePatch(const PatchInfo& patch_info);
|
extern bool IsGloballyToggleablePatch(const PatchInfo& patch_info);
|
||||||
|
|
||||||
|
extern const char* PlaceToString(std::optional<patch_place_type> place);
|
||||||
} // namespace Patch
|
} // namespace Patch
|
||||||
|
|||||||
@ -56,8 +56,9 @@ bool InputRecording::create(const std::string& fileName, const bool fromSaveStat
|
|||||||
m_initial_load_complete = true;
|
m_initial_load_complete = true;
|
||||||
m_watching_for_rerecords = true;
|
m_watching_for_rerecords = true;
|
||||||
setStartingFrame(g_FrameCount);
|
setStartingFrame(g_FrameCount);
|
||||||
// TODO - error handling
|
VMManager::SaveState(savestatePath.c_str(), true, false, [](const std::string& error) {
|
||||||
VMManager::SaveState(savestatePath.c_str());
|
SaveState_ReportSaveErrorOSD(error, std::nullopt);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -93,7 +94,7 @@ bool InputRecording::play(const std::string& filename)
|
|||||||
if (!FileSystem::FileExists(savestatePath.c_str()))
|
if (!FileSystem::FileExists(savestatePath.c_str()))
|
||||||
{
|
{
|
||||||
InputRec::consoleLog(fmt::format("Could not locate savestate file at location - {}", savestatePath));
|
InputRec::consoleLog(fmt::format("Could not locate savestate file at location - {}", savestatePath));
|
||||||
InputRec::log(TRANSLATE_STR("InputRecording", "Savestate load failed for input recording"), Host::OSD_ERROR_DURATION);
|
InputRec::log(TRANSLATE_STR("InputRecording", "Failed to load state for input recording"), Host::OSD_ERROR_DURATION);
|
||||||
m_file.close();
|
m_file.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -103,7 +104,7 @@ bool InputRecording::play(const std::string& filename)
|
|||||||
const auto loaded = VMManager::LoadState(savestatePath.c_str());
|
const auto loaded = VMManager::LoadState(savestatePath.c_str());
|
||||||
if (!loaded)
|
if (!loaded)
|
||||||
{
|
{
|
||||||
InputRec::log(TRANSLATE_STR("InputRecording", "Savestate load failed for input recording, unsupported version?"), Host::OSD_ERROR_DURATION);
|
InputRec::log(TRANSLATE_STR("InputRecording", "Failed to load state for input recording, unsupported version?"), Host::OSD_ERROR_DURATION);
|
||||||
m_file.close();
|
m_file.close();
|
||||||
m_is_active = false;
|
m_is_active = false;
|
||||||
return false;
|
return false;
|
||||||
@ -343,7 +344,7 @@ void InputRecording::adjustFrameCounterOnReRecord(u32 newFrameCounter)
|
|||||||
if (newFrameCounter > m_starting_frame + m_file.getTotalFrames())
|
if (newFrameCounter > m_starting_frame + m_file.getTotalFrames())
|
||||||
{
|
{
|
||||||
InputRec::consoleLog("Warning, you've loaded PCSX2 emulation to a point after the end of the original recording. This should be avoided.");
|
InputRec::consoleLog("Warning, you've loaded PCSX2 emulation to a point after the end of the original recording. This should be avoided.");
|
||||||
InputRec::consoleLog("Savestate's framecount has been ignored, using the max length of the recording instead.");
|
InputRec::consoleLog("Save state's framecount has been ignored, using the max length of the recording instead.");
|
||||||
m_frame_counter = m_file.getTotalFrames();
|
m_frame_counter = m_file.getTotalFrames();
|
||||||
if (getControls().isReplaying())
|
if (getControls().isReplaying())
|
||||||
{
|
{
|
||||||
@ -354,7 +355,7 @@ void InputRecording::adjustFrameCounterOnReRecord(u32 newFrameCounter)
|
|||||||
if (newFrameCounter < m_starting_frame)
|
if (newFrameCounter < m_starting_frame)
|
||||||
{
|
{
|
||||||
InputRec::consoleLog("Warning, you've loaded PCSX2 emulation to a point before the start of the original recording. This should be avoided.");
|
InputRec::consoleLog("Warning, you've loaded PCSX2 emulation to a point before the start of the original recording. This should be avoided.");
|
||||||
InputRec::consoleLog("Savestate's framecount has been ignored, starting from the beginning in replay mode.");
|
InputRec::consoleLog("Save state's framecount has been ignored, starting from the beginning in replay mode.");
|
||||||
m_frame_counter = 0;
|
m_frame_counter = 0;
|
||||||
if (getControls().isRecording())
|
if (getControls().isRecording())
|
||||||
{
|
{
|
||||||
@ -395,8 +396,7 @@ void InputRecording::InformGSThread()
|
|||||||
TinyString frame_data_message = TinyString::from_format(TRANSLATE_FS("InputRecording", "Frame: {}/{} ({})"), g_InputRecording.getFrameCounter(), g_InputRecording.getData().getTotalFrames(), g_InputRecording.getFrameCounterStateless());
|
TinyString frame_data_message = TinyString::from_format(TRANSLATE_FS("InputRecording", "Frame: {}/{} ({})"), g_InputRecording.getFrameCounter(), g_InputRecording.getData().getTotalFrames(), g_InputRecording.getFrameCounterStateless());
|
||||||
TinyString undo_count_message = TinyString::from_format(TRANSLATE_FS("InputRecording", "Undo Count: {}"), g_InputRecording.getData().getUndoCount());
|
TinyString undo_count_message = TinyString::from_format(TRANSLATE_FS("InputRecording", "Undo Count: {}"), g_InputRecording.getData().getUndoCount());
|
||||||
|
|
||||||
MTGS::RunOnGSThread([recording_active_message, frame_data_message, undo_count_message](bool is_recording = g_InputRecording.getControls().isRecording())
|
MTGS::RunOnGSThread([recording_active_message, frame_data_message, undo_count_message](bool is_recording = g_InputRecording.getControls().isRecording()) {
|
||||||
{
|
|
||||||
g_InputRecordingData.is_recording = is_recording;
|
g_InputRecordingData.is_recording = is_recording;
|
||||||
g_InputRecordingData.recording_active_message = recording_active_message;
|
g_InputRecordingData.recording_active_message = recording_active_message;
|
||||||
g_InputRecordingData.frame_data_message = frame_data_message;
|
g_InputRecordingData.frame_data_message = frame_data_message;
|
||||||
|
|||||||
@ -581,9 +581,10 @@ bool Pad::Freeze(StateWrapper& sw)
|
|||||||
|
|
||||||
const auto& [port, slot] = sioConvertPadToPortAndSlot(unifiedSlot);
|
const auto& [port, slot] = sioConvertPadToPortAndSlot(unifiedSlot);
|
||||||
Host::AddIconOSDMessage(fmt::format("UnfreezePad{}Changed", unifiedSlot), ICON_FA_GAMEPAD,
|
Host::AddIconOSDMessage(fmt::format("UnfreezePad{}Changed", unifiedSlot), ICON_FA_GAMEPAD,
|
||||||
|
//: {0} and {1} are the port and multitap slot, {2} and {3} are controller types (e.g. "DualShock 2", "Jogcon")
|
||||||
fmt::format(TRANSLATE_FS("Pad",
|
fmt::format(TRANSLATE_FS("Pad",
|
||||||
"Controller port {0}, slot {1} has a {2} connected, but the save state has a "
|
"Controller port {0}, slot {1} has a {2} connected, but the save state has a "
|
||||||
"{3}.\nEjecting {3} and replacing it with {2}."),
|
"{3}.\nEjecting {2} and replacing it with {3}."),
|
||||||
port, slot,
|
port, slot,
|
||||||
GetControllerTypeName(currentPad ? currentPad->GetType() : Pad::ControllerType::NotConnected),
|
GetControllerTypeName(currentPad ? currentPad->GetType() : Pad::ControllerType::NotConnected),
|
||||||
GetControllerTypeName(statePadType)));
|
GetControllerTypeName(statePadType)));
|
||||||
@ -698,7 +699,7 @@ void Pad::SetMacroButtonState(InputBindingKey& key, u32 pad, u32 index, bool sta
|
|||||||
}
|
}
|
||||||
if (mb.active_buttons.find(key.bits) != mb.active_buttons.end())
|
if (mb.active_buttons.find(key.bits) != mb.active_buttons.end())
|
||||||
mb.active_buttons.erase(key.bits);
|
mb.active_buttons.erase(key.bits);
|
||||||
|
|
||||||
mb.active_buttons.emplace(key.bits, state);
|
mb.active_buttons.emplace(key.bits, state);
|
||||||
|
|
||||||
if (mb.active_buttons.size() != binding_count)
|
if (mb.active_buttons.size() != binding_count)
|
||||||
@ -759,4 +760,4 @@ void Pad::UpdateMacroButtons()
|
|||||||
ApplyMacroButton(pad, mb);
|
ApplyMacroButton(pad, mb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@
|
|||||||
#include "common/StringUtil.h"
|
#include "common/StringUtil.h"
|
||||||
#include "common/ZipHelpers.h"
|
#include "common/ZipHelpers.h"
|
||||||
|
|
||||||
|
#include "IconsFontAwesome6.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
|
||||||
#include <csetjmp>
|
#include <csetjmp>
|
||||||
@ -1038,14 +1039,18 @@ static bool SaveState_AddToZip(zip_t* zf, ArchiveEntryList* srclist, SaveStateSc
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SaveState_ZipToDisk(std::unique_ptr<ArchiveEntryList> srclist, std::unique_ptr<SaveStateScreenshotData> screenshot, const char* filename)
|
bool SaveState_ZipToDisk(
|
||||||
|
std::unique_ptr<ArchiveEntryList> srclist, std::unique_ptr<SaveStateScreenshotData> screenshot,
|
||||||
|
const char* filename, Error* error)
|
||||||
{
|
{
|
||||||
zip_error_t ze = {};
|
zip_error_t ze = {};
|
||||||
zip_source_t* zs = zip_source_file_create(filename, 0, 0, &ze);
|
zip_source_t* zs = zip_source_file_create(filename, 0, 0, &ze);
|
||||||
zip_t* zf = nullptr;
|
zip_t* zf = nullptr;
|
||||||
if (zs && !(zf = zip_open_from_source(zs, ZIP_CREATE | ZIP_TRUNCATE, &ze)))
|
if (zs && !(zf = zip_open_from_source(zs, ZIP_CREATE | ZIP_TRUNCATE, &ze)))
|
||||||
{
|
{
|
||||||
Console.Error("Failed to open zip file '%s' for save state: %s", filename, zip_error_strerror(&ze));
|
Error::SetStringFmt(error,
|
||||||
|
TRANSLATE_FS("SaveState", "Failed to open zip file '{}' for save state: {}."),
|
||||||
|
filename, zip_error_strerror(&ze));
|
||||||
|
|
||||||
// have to clean up source
|
// have to clean up source
|
||||||
zip_source_free(zs);
|
zip_source_free(zs);
|
||||||
@ -1055,13 +1060,21 @@ bool SaveState_ZipToDisk(std::unique_ptr<ArchiveEntryList> srclist, std::unique_
|
|||||||
// discard zip file if we fail saving something
|
// discard zip file if we fail saving something
|
||||||
if (!SaveState_AddToZip(zf, srclist.get(), screenshot.get()))
|
if (!SaveState_AddToZip(zf, srclist.get(), screenshot.get()))
|
||||||
{
|
{
|
||||||
Console.Error("Failed to save state to zip file '%s'", filename);
|
Error::SetStringFmt(error,
|
||||||
|
TRANSLATE_FS("SaveState", "Failed to save state to zip file '{}'."), filename);
|
||||||
zip_discard(zf);
|
zip_discard(zf);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// force the zip to close, this is the expensive part with libzip.
|
// force the zip to close, this is the expensive part with libzip.
|
||||||
zip_close(zf);
|
if (zip_close(zf) != 0)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error,
|
||||||
|
TRANSLATE_FS("SaveState", "Failed to save state to zip file '{}': {}."), filename, zip_strerror(zf));
|
||||||
|
zip_discard(zf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1231,3 +1244,37 @@ bool SaveState_UnzipFromDisk(const std::string& filename, Error* error)
|
|||||||
PostLoadPrep();
|
PostLoadPrep();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SaveState_ReportLoadErrorOSD(const std::string& message, std::optional<s32> slot, bool backup)
|
||||||
|
{
|
||||||
|
std::string full_message;
|
||||||
|
if (slot.has_value())
|
||||||
|
{
|
||||||
|
if (backup)
|
||||||
|
full_message = fmt::format(
|
||||||
|
TRANSLATE_FS("SaveState", "Failed to load state from backup slot {}: {}"), *slot, message);
|
||||||
|
else
|
||||||
|
full_message = fmt::format(
|
||||||
|
TRANSLATE_FS("SaveState", "Failed to load state from slot {}: {}"), *slot, message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
full_message = fmt::format(TRANSLATE_FS("SaveState", "Failed to load state: {}"), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
Host::AddIconOSDMessage("LoadState", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||||
|
full_message, Host::OSD_WARNING_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveState_ReportSaveErrorOSD(const std::string& message, std::optional<s32> slot)
|
||||||
|
{
|
||||||
|
std::string full_message;
|
||||||
|
if (slot.has_value())
|
||||||
|
full_message = fmt::format(
|
||||||
|
TRANSLATE_FS("SaveState", "Failed to save state to slot {}: {}"), *slot, message);
|
||||||
|
else
|
||||||
|
full_message = fmt::format(TRANSLATE_FS("SaveState", "Failed to save state: {}"), message);
|
||||||
|
|
||||||
|
Host::AddIconOSDMessage("SaveState", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||||
|
full_message, Host::OSD_WARNING_DURATION);
|
||||||
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -53,7 +54,9 @@ class ArchiveEntryList;
|
|||||||
// These functions assume that the caller has paused the core thread.
|
// These functions assume that the caller has paused the core thread.
|
||||||
extern std::unique_ptr<ArchiveEntryList> SaveState_DownloadState(Error* error);
|
extern std::unique_ptr<ArchiveEntryList> SaveState_DownloadState(Error* error);
|
||||||
extern std::unique_ptr<SaveStateScreenshotData> SaveState_SaveScreenshot();
|
extern std::unique_ptr<SaveStateScreenshotData> SaveState_SaveScreenshot();
|
||||||
extern bool SaveState_ZipToDisk(std::unique_ptr<ArchiveEntryList> srclist, std::unique_ptr<SaveStateScreenshotData> screenshot, const char* filename);
|
extern bool SaveState_ZipToDisk(
|
||||||
|
std::unique_ptr<ArchiveEntryList> srclist, std::unique_ptr<SaveStateScreenshotData> screenshot,
|
||||||
|
const char* filename, Error* error);
|
||||||
extern bool SaveState_ReadScreenshot(const std::string& filename, u32* out_width, u32* out_height, std::vector<u32>* out_pixels);
|
extern bool SaveState_ReadScreenshot(const std::string& filename, u32* out_width, u32* out_height, std::vector<u32>* out_pixels);
|
||||||
extern bool SaveState_UnzipFromDisk(const std::string& filename, Error* error);
|
extern bool SaveState_UnzipFromDisk(const std::string& filename, Error* error);
|
||||||
|
|
||||||
@ -353,3 +356,6 @@ public:
|
|||||||
void FreezeMem(void* data, int size) override;
|
void FreezeMem(void* data, int size) override;
|
||||||
bool IsSaving() const override { return false; }
|
bool IsSaving() const override { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void SaveState_ReportLoadErrorOSD(const std::string& message, std::optional<s32> slot, bool backup);
|
||||||
|
void SaveState_ReportSaveErrorOSD(const std::string& message, std::optional<s32> slot);
|
||||||
|
|||||||
@ -1243,7 +1243,7 @@ namespace usb_msd
|
|||||||
{
|
{
|
||||||
static constexpr const SettingInfo settings[] = {
|
static constexpr const SettingInfo settings[] = {
|
||||||
{SettingInfo::Type::Path, "ImagePathMsd", TRANSLATE_NOOP("USB", "Image Path"),
|
{SettingInfo::Type::Path, "ImagePathMsd", TRANSLATE_NOOP("USB", "Image Path"),
|
||||||
TRANSLATE_NOOP("USB", "Sets the path to image which will back the virtual mass storage device.")},
|
TRANSLATE_NOOP("USB", "Sets the path to the disk image which will back the virtual mass storage device.")},
|
||||||
};
|
};
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
@ -1251,7 +1251,7 @@ namespace usb_msd
|
|||||||
{
|
{
|
||||||
static constexpr const SettingInfo settings[] = {
|
static constexpr const SettingInfo settings[] = {
|
||||||
{SettingInfo::Type::Path, "ImagePathMsac", TRANSLATE_NOOP("USB", "Image Path"),
|
{SettingInfo::Type::Path, "ImagePathMsac", TRANSLATE_NOOP("USB", "Image Path"),
|
||||||
TRANSLATE_NOOP("USB", "Sets the path to image which will back the virtual mass storage device.")},
|
TRANSLATE_NOOP("USB", "Sets the path to the disk image which will back the virtual mass storage device.")},
|
||||||
};
|
};
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -115,13 +115,13 @@ namespace VMManager
|
|||||||
|
|
||||||
static std::string GetCurrentSaveStateFileName(s32 slot, bool backup = false);
|
static std::string GetCurrentSaveStateFileName(s32 slot, bool backup = false);
|
||||||
static bool DoLoadState(const char* filename, Error* error = nullptr);
|
static bool DoLoadState(const char* filename, Error* error = nullptr);
|
||||||
static bool DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state);
|
static void DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state, std::function<void(const std::string&)> error_callback);
|
||||||
static void ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
static void ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
||||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, const char* filename,
|
std::unique_ptr<SaveStateScreenshotData> screenshot, const char* filename,
|
||||||
s32 slot_for_message);
|
s32 slot_for_message, std::function<void(const std::string&)> error_callback);
|
||||||
static void ZipSaveStateOnThread(std::unique_ptr<ArchiveEntryList> elist,
|
static void ZipSaveStateOnThread(std::unique_ptr<ArchiveEntryList> elist,
|
||||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, std::string filename,
|
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string filename,
|
||||||
s32 slot_for_message);
|
s32 slot_for_message, std::function<void(const std::string&)> error_callback);
|
||||||
|
|
||||||
static void LoadSettings();
|
static void LoadSettings();
|
||||||
static void LoadCoreSettings(SettingsInterface& si);
|
static void LoadCoreSettings(SettingsInterface& si);
|
||||||
@ -1617,8 +1617,13 @@ void VMManager::Shutdown(bool save_resume_state)
|
|||||||
if (!GSDumpReplayer::IsReplayingDump() && save_resume_state)
|
if (!GSDumpReplayer::IsReplayingDump() && save_resume_state)
|
||||||
{
|
{
|
||||||
std::string resume_file_name(GetCurrentSaveStateFileName(-1));
|
std::string resume_file_name(GetCurrentSaveStateFileName(-1));
|
||||||
if (!resume_file_name.empty() && !DoSaveState(resume_file_name.c_str(), -1, true, false))
|
if (!resume_file_name.empty())
|
||||||
Console.Error("Failed to save resume state");
|
{
|
||||||
|
DoSaveState(resume_file_name.c_str(), -1, true, false, [](const std::string& error) {
|
||||||
|
Host::AddIconOSDMessage("SaveResumeState", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||||
|
fmt::format(TRANSLATE_FS("VMManager", "Failed to save resume state: {}"), error), Host::OSD_QUICK_DURATION);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// end input recording before clearing state
|
// end input recording before clearing state
|
||||||
@ -1829,7 +1834,7 @@ bool VMManager::DoLoadState(const char* filename, Error* error)
|
|||||||
{
|
{
|
||||||
if (GSDumpReplayer::IsReplayingDump())
|
if (GSDumpReplayer::IsReplayingDump())
|
||||||
{
|
{
|
||||||
Error::SetString(error, TRANSLATE_STR("VMManager", "Cannot load save state while replaying GS dump."));
|
Error::SetString(error, TRANSLATE_STR("VMManager", "Cannot load state while replaying a GS dump."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1849,21 +1854,20 @@ bool VMManager::DoLoadState(const char* filename, Error* error)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state)
|
void VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state, std::function<void(const std::string&)> error_callback)
|
||||||
{
|
{
|
||||||
if (GSDumpReplayer::IsReplayingDump())
|
if (GSDumpReplayer::IsReplayingDump())
|
||||||
return false;
|
{
|
||||||
|
error_callback(TRANSLATE_STR("VMManager", "Cannot save state while replaying a GS dump."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::string osd_key(fmt::format("SaveStateSlot{}", slot_for_message));
|
|
||||||
Error error;
|
Error error;
|
||||||
|
|
||||||
std::unique_ptr<ArchiveEntryList> elist = SaveState_DownloadState(&error);
|
std::unique_ptr<ArchiveEntryList> elist = SaveState_DownloadState(&error);
|
||||||
if (!elist)
|
if (!elist)
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_TRIANGLE_EXCLAMATION,
|
error_callback(error.GetDescription());
|
||||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state: {}."), error.GetDescription()),
|
return;
|
||||||
Host::OSD_ERROR_DURATION);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SaveStateScreenshotData> screenshot = SaveState_SaveScreenshot();
|
std::unique_ptr<SaveStateScreenshotData> screenshot = SaveState_SaveScreenshot();
|
||||||
@ -1874,10 +1878,10 @@ bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip
|
|||||||
Console.WriteLn(fmt::format("Creating save state backup {}...", backup_filename));
|
Console.WriteLn(fmt::format("Creating save state backup {}...", backup_filename));
|
||||||
if (!FileSystem::RenamePath(filename, backup_filename.c_str()))
|
if (!FileSystem::RenamePath(filename, backup_filename.c_str()))
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage(osd_key, ICON_FA_TRIANGLE_EXCLAMATION,
|
error_callback(fmt::format(
|
||||||
fmt::format(
|
TRANSLATE_FS("VMManager", "Cannot back up old save state '{}'."),
|
||||||
TRANSLATE_FS("VMManager", "Failed to back up old save state {}."), Path::GetFileName(filename)),
|
Path::GetFileName(filename)));
|
||||||
Host::OSD_ERROR_DURATION);
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1886,48 +1890,48 @@ bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip
|
|||||||
// lock order here is important; the thread could exit before we resume here.
|
// lock order here is important; the thread could exit before we resume here.
|
||||||
std::unique_lock lock(s_save_state_threads_mutex);
|
std::unique_lock lock(s_save_state_threads_mutex);
|
||||||
s_save_state_threads.emplace_back(&VMManager::ZipSaveStateOnThread, std::move(elist), std::move(screenshot),
|
s_save_state_threads.emplace_back(&VMManager::ZipSaveStateOnThread, std::move(elist), std::move(screenshot),
|
||||||
std::move(osd_key), std::string(filename), slot_for_message);
|
std::string(filename), slot_for_message, std::move(error_callback));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ZipSaveState(std::move(elist), std::move(screenshot), std::move(osd_key), filename, slot_for_message);
|
ZipSaveState(
|
||||||
|
std::move(elist), std::move(screenshot), filename, slot_for_message, std::move(error_callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
Host::OnSaveStateSaved(filename);
|
Host::OnSaveStateSaved(filename);
|
||||||
MemcardBusy::CheckSaveStateDependency();
|
MemcardBusy::CheckSaveStateDependency();
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
void VMManager::ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
||||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, const char* filename,
|
std::unique_ptr<SaveStateScreenshotData> screenshot, const char* filename,
|
||||||
s32 slot_for_message)
|
s32 slot_for_message, std::function<void(const std::string&)> error_callback)
|
||||||
{
|
{
|
||||||
Common::Timer timer;
|
Common::Timer timer;
|
||||||
|
|
||||||
if (SaveState_ZipToDisk(std::move(elist), std::move(screenshot), filename))
|
Error error;
|
||||||
|
if (!SaveState_ZipToDisk(std::move(elist), std::move(screenshot), filename, &error))
|
||||||
{
|
{
|
||||||
if (slot_for_message >= 0 && VMManager::HasValidVM())
|
error_callback(error.GetDescription());
|
||||||
{
|
return;
|
||||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_FLOPPY_DISK,
|
|
||||||
fmt::format(TRANSLATE_FS("VMManager", "State saved to slot {}."), slot_for_message),
|
|
||||||
Host::OSD_QUICK_DURATION);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (slot_for_message >= 0 && VMManager::HasValidVM())
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_TRIANGLE_EXCLAMATION,
|
Host::AddIconOSDMessage(fmt::format("SaveStateSlot{}", slot_for_message), ICON_FA_FLOPPY_DISK,
|
||||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state to slot {}."), slot_for_message,
|
fmt::format(TRANSLATE_FS("VMManager", "Saved state to slot {}."), slot_for_message),
|
||||||
Host::OSD_ERROR_DURATION));
|
Host::OSD_QUICK_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
DevCon.WriteLn("Zipping save state to '%s' took %.2f ms", filename, timer.GetTimeMilliseconds());
|
DevCon.WriteLn("Zipping save state to '%s' took %.2f ms", filename, timer.GetTimeMilliseconds());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::ZipSaveStateOnThread(std::unique_ptr<ArchiveEntryList> elist,
|
void VMManager::ZipSaveStateOnThread(std::unique_ptr<ArchiveEntryList> elist,
|
||||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, std::string filename,
|
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string filename,
|
||||||
s32 slot_for_message)
|
s32 slot_for_message, std::function<void(const std::string&)> error_callback)
|
||||||
{
|
{
|
||||||
ZipSaveState(std::move(elist), std::move(screenshot), std::move(osd_key), filename.c_str(), slot_for_message);
|
ZipSaveState(
|
||||||
|
std::move(elist), std::move(screenshot), filename.c_str(), slot_for_message, std::move(error_callback));
|
||||||
|
|
||||||
// remove ourselves from the thread list. if we're joining, we might not be in there.
|
// remove ourselves from the thread list. if we're joining, we might not be in there.
|
||||||
const auto this_id = std::this_thread::get_id();
|
const auto this_id = std::this_thread::get_id();
|
||||||
@ -1985,23 +1989,25 @@ bool VMManager::LoadState(const char* filename, Error* error)
|
|||||||
if (Achievements::IsHardcoreModeActive())
|
if (Achievements::IsHardcoreModeActive())
|
||||||
{
|
{
|
||||||
Error::SetString(error,
|
Error::SetString(error,
|
||||||
TRANSLATE_STR("VMManager", "Cannot load save state while RetroAchievements Hardcore Mode is active."));
|
TRANSLATE_STR("VMManager", "Cannot load state while RetroAchievements Hardcore Mode is active."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MemcardBusy::IsBusy())
|
if (MemcardBusy::IsBusy())
|
||||||
{
|
{
|
||||||
Error::SetString(error,
|
Error::SetString(error,
|
||||||
TRANSLATE_STR("VMManager", "Memory card is busy."));
|
TRANSLATE_STR("VMManager", "The memory card is busy, so the state load operation has been cancelled to prevent data loss."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Save the current state so we don't need to reset.
|
// TODO: Save the current state so we don't need to reset.
|
||||||
if (DoLoadState(filename, error))
|
if (!DoLoadState(filename, error))
|
||||||
return true;
|
{
|
||||||
|
Reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Reset();
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VMManager::LoadStateFromSlot(s32 slot, bool backup, Error* error)
|
bool VMManager::LoadStateFromSlot(s32 slot, bool backup, Error* error)
|
||||||
@ -2009,74 +2015,84 @@ bool VMManager::LoadStateFromSlot(s32 slot, bool backup, Error* error)
|
|||||||
const std::string filename = GetCurrentSaveStateFileName(slot, backup);
|
const std::string filename = GetCurrentSaveStateFileName(slot, backup);
|
||||||
if (filename.empty() || !FileSystem::FileExists(filename.c_str()))
|
if (filename.empty() || !FileSystem::FileExists(filename.c_str()))
|
||||||
{
|
{
|
||||||
if (backup)
|
Error::SetString(error, TRANSLATE_STR("VMManager", "The save slot is empty."));
|
||||||
Error::SetStringFmt(error,
|
|
||||||
TRANSLATE_FS("VMManager", "There is no save state in backup slot {}."), slot);
|
|
||||||
else
|
|
||||||
Error::SetStringFmt(error,
|
|
||||||
TRANSLATE_FS("VMManager", "There is no save state in slot {}."), slot);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Achievements::IsHardcoreModeActive())
|
if (Achievements::IsHardcoreModeActive())
|
||||||
{
|
{
|
||||||
if (backup)
|
Error::SetString(error,
|
||||||
Error::SetStringFmt(error,
|
TRANSLATE_STR("VMManager", "Cannot load state while RetroAchievements Hardcore Mode is active."));
|
||||||
TRANSLATE_FS("VMManager", "Cannot load save state from backup slot {} while RetroAchievements Hardcore Mode is active."), slot);
|
|
||||||
else
|
|
||||||
Error::SetStringFmt(error,
|
|
||||||
TRANSLATE_FS("VMManager", "Cannot load save state from slot {} while RetroAchievements Hardcore Mode is active."), slot);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MemcardBusy::IsBusy())
|
if (MemcardBusy::IsBusy())
|
||||||
{
|
{
|
||||||
if (backup)
|
Error::SetString(error,
|
||||||
Error::SetStringFmt(error,
|
TRANSLATE_STR("VMManager",
|
||||||
TRANSLATE_FS("VMManager", "Failed to load save state from backup slot {} (memory card is busy)."), slot);
|
"The memory card is busy, so the state load operation has been cancelled to prevent data loss."));
|
||||||
else
|
|
||||||
Error::SetStringFmt(error,
|
|
||||||
TRANSLATE_FS("VMManager", "Failed to load save state from slot {} (memory card is busy)."), slot);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN,
|
if (!DoLoadState(filename.c_str(), error))
|
||||||
fmt::format(TRANSLATE_FS("VMManager", "Loading {} from slot {}..."), backup ? TRANSLATE("VMManager", "backup state") : TRANSLATE("VMManager", "state"), slot), Host::OSD_QUICK_DURATION);
|
return false;
|
||||||
|
|
||||||
return DoLoadState(filename.c_str(), error);
|
if (backup)
|
||||||
|
{
|
||||||
|
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN,
|
||||||
|
fmt::format(TRANSLATE_FS("VMManager", "Loaded state from backup slot {}."), slot),
|
||||||
|
Host::OSD_QUICK_DURATION);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN,
|
||||||
|
fmt::format(TRANSLATE_FS("VMManager", "Loaded state from slot {}."), slot),
|
||||||
|
Host::OSD_QUICK_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VMManager::SaveState(const char* filename, bool zip_on_thread, bool backup_old_state)
|
void VMManager::SaveState(
|
||||||
|
const char* filename, bool zip_on_thread, bool backup_old_state, std::function<void(const std::string&)> error_callback)
|
||||||
{
|
{
|
||||||
if (MemcardBusy::IsBusy())
|
if (MemcardBusy::IsBusy())
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
error_callback(TRANSLATE_STR("VMManager",
|
||||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state (Memory card is busy)")),
|
"The memory card is busy, so the state save operation has been cancelled to prevent data loss."));
|
||||||
Host::OSD_QUICK_DURATION);
|
return;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return DoSaveState(filename, -1, zip_on_thread, backup_old_state);
|
DoSaveState(filename, -1, zip_on_thread, backup_old_state, std::move(error_callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VMManager::SaveStateToSlot(s32 slot, bool zip_on_thread)
|
void VMManager::SaveStateToSlot(s32 slot, bool zip_on_thread, std::function<void(const std::string&)> error_callback)
|
||||||
{
|
{
|
||||||
const std::string filename(GetCurrentSaveStateFileName(slot));
|
const std::string filename(GetCurrentSaveStateFileName(slot));
|
||||||
if (filename.empty())
|
if (filename.empty())
|
||||||
return false;
|
{
|
||||||
|
error_callback(TRANSLATE_STR("VMManager", "Cannot generate filename for save state."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (MemcardBusy::IsBusy())
|
if (MemcardBusy::IsBusy())
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
error_callback(TRANSLATE_STR("VMManager",
|
||||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state to slot {} (Memory card is busy)"), slot),
|
"The memory card is busy, so the state save operation has been cancelled to prevent data loss."));
|
||||||
Host::OSD_QUICK_DURATION);
|
return;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if it takes more than a minute.. well.. wtf.
|
// if it takes more than a minute.. well.. wtf.
|
||||||
Host::AddIconOSDMessage(fmt::format("SaveStateSlot{}", slot), ICON_FA_FLOPPY_DISK,
|
Host::AddIconOSDMessage(fmt::format("SaveStateSlot{}", slot), ICON_FA_FLOPPY_DISK,
|
||||||
fmt::format(TRANSLATE_FS("VMManager", "Saving state to slot {}..."), slot), 60.0f);
|
fmt::format(TRANSLATE_FS("VMManager", "Saving state to slot {}..."), slot), 60.0f);
|
||||||
return DoSaveState(filename.c_str(), slot, zip_on_thread, EmuConfig.BackupSavestate);
|
|
||||||
|
auto callback = [error_callback = std::move(error_callback), slot](const std::string& error) {
|
||||||
|
Host::RemoveKeyedOSDMessage(fmt::format("SaveStateSlot{}", slot));
|
||||||
|
error_callback(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
return DoSaveState(
|
||||||
|
filename.c_str(), slot, zip_on_thread, EmuConfig.BackupSavestate, std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
LimiterModeType VMManager::GetLimiterMode()
|
LimiterModeType VMManager::GetLimiterMode()
|
||||||
@ -2816,8 +2832,8 @@ void VMManager::Internal::EntryPointCompilingOnCPUThread()
|
|||||||
|
|
||||||
HandleELFChange(true);
|
HandleELFChange(true);
|
||||||
|
|
||||||
Patch::ApplyLoadedPatches(Patch::PPT_ONCE_ON_LOAD);
|
Patch::ApplyBootPatches();
|
||||||
Patch::ApplyLoadedPatches(Patch::PPT_COMBINED_0_1);
|
|
||||||
// If the config changes at this point, it's a reset, so the game doesn't currently know about the memcard
|
// If the config changes at this point, it's a reset, so the game doesn't currently know about the memcard
|
||||||
// so there's no need to leave the eject running.
|
// so there's no need to leave the eject running.
|
||||||
FileMcd_CancelEject();
|
FileMcd_CancelEject();
|
||||||
@ -2833,8 +2849,7 @@ void VMManager::Internal::VSyncOnCPUThread()
|
|||||||
{
|
{
|
||||||
Pad::UpdateMacroButtons();
|
Pad::UpdateMacroButtons();
|
||||||
|
|
||||||
Patch::ApplyLoadedPatches(Patch::PPT_CONTINUOUSLY);
|
Patch::ApplyVsyncPatches();
|
||||||
Patch::ApplyLoadedPatches(Patch::PPT_COMBINED_0_1);
|
|
||||||
|
|
||||||
// Frame advance must be done *before* pumping messages, because otherwise
|
// Frame advance must be done *before* pumping messages, because otherwise
|
||||||
// we'll immediately reduce the counter we just set.
|
// we'll immediately reduce the counter we just set.
|
||||||
|
|||||||
@ -165,10 +165,11 @@ namespace VMManager
|
|||||||
bool LoadStateFromSlot(s32 slot, bool backup = false, Error* error = nullptr);
|
bool LoadStateFromSlot(s32 slot, bool backup = false, Error* error = nullptr);
|
||||||
|
|
||||||
/// Saves state to the specified filename.
|
/// Saves state to the specified filename.
|
||||||
bool SaveState(const char* filename, bool zip_on_thread = true, bool backup_old_state = false);
|
void SaveState(const char* filename, bool zip_on_thread, bool backup_old_state,
|
||||||
|
std::function<void(const std::string&)> error_callback);
|
||||||
|
|
||||||
/// Saves state to the specified slot.
|
/// Saves state to the specified slot.
|
||||||
bool SaveStateToSlot(s32 slot, bool zip_on_thread = true);
|
void SaveStateToSlot(s32 slot, bool zip_on_thread, std::function<void(const std::string&)> error_callback);
|
||||||
|
|
||||||
/// Waits until all compressing save states have finished saving to disk.
|
/// Waits until all compressing save states have finished saving to disk.
|
||||||
void WaitForSaveStateFlush();
|
void WaitForSaveStateFlush();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user