mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
191 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6e2185c9c | ||
|
|
08edc8dfab | ||
|
|
ec0760c03e | ||
|
|
b53dfed032 | ||
|
|
96599f26a5 | ||
|
|
c049a7ac76 | ||
|
|
34dabc77c1 | ||
|
|
b4deb6a4e2 | ||
|
|
dd91c0aac2 | ||
|
|
fd983946f5 | ||
|
|
fb18fdf5b7 | ||
|
|
bc7670aa3b | ||
|
|
fe76a4575c | ||
|
|
6addc7cf5f | ||
|
|
eb8b6f4fb5 | ||
|
|
e2a60b7280 | ||
|
|
fe2d0cb514 | ||
|
|
3362ca25be | ||
|
|
c919c2a6fd | ||
|
|
5a70075169 | ||
|
|
42c576cf99 | ||
|
|
1fd26c919b | ||
|
|
c957b558e0 | ||
|
|
ec047c5972 | ||
|
|
08388d12d1 | ||
|
|
850aeaf05e | ||
|
|
6195f4b40e | ||
|
|
92baf77509 | ||
|
|
ab1cdb4c9d | ||
|
|
4f4ff00ecf | ||
|
|
6fe97b42c3 | ||
|
|
c9ac4960bc | ||
|
|
e4d7d22e78 | ||
|
|
eb83cb70ea | ||
|
|
59210dffa9 | ||
|
|
c76cca874b | ||
|
|
d989ce5b44 | ||
|
|
fbc95f2c86 | ||
|
|
9fb8dacadb | ||
|
|
d332aee542 | ||
|
|
f2c97fc2c3 | ||
|
|
5ab84aaa29 | ||
|
|
9842b11815 | ||
|
|
083fb5a1e6 | ||
|
|
98cdd3446b | ||
|
|
9bcbf43695 | ||
|
|
e3c988aa8b | ||
|
|
06be543d32 | ||
|
|
1fd22dcc1c | ||
|
|
e3afdde981 | ||
|
|
698df49e5e | ||
|
|
ff5c90ec5e | ||
|
|
1e075d23b2 | ||
|
|
2b172903b9 | ||
|
|
4654a3ef6c | ||
|
|
9996061f74 | ||
|
|
247a4c40d1 | ||
|
|
1ffbdd9c08 | ||
|
|
f67c0cbd2e | ||
|
|
ff7cc0867b | ||
|
|
ac1a6d3348 | ||
|
|
582bba6c91 | ||
|
|
aaf156478e | ||
|
|
0539c177ab | ||
|
|
fb1323b72f | ||
|
|
dc557dd0e5 | ||
|
|
2d0cfc9c2c | ||
|
|
625a25cd50 | ||
|
|
b8a29d1cd8 | ||
|
|
0fabdf9a01 | ||
|
|
9c3ae795c8 | ||
|
|
de26226fa1 | ||
|
|
121920c074 | ||
|
|
05e19470b2 | ||
|
|
b6680e4aca | ||
|
|
f9d70af841 | ||
|
|
7587581d1f | ||
|
|
8f19976c10 | ||
|
|
8567d68433 | ||
|
|
6542301566 | ||
|
|
a359f77cf6 | ||
|
|
4c9a81f3d8 | ||
|
|
9234b493a3 | ||
|
|
f84425b67c | ||
|
|
8a0c1874dd | ||
|
|
fa23628ae2 | ||
|
|
8a594e673d | ||
|
|
92b9390c51 | ||
|
|
c5c5b2a7b9 | ||
|
|
32a9d0e48b | ||
|
|
80a961bb25 | ||
|
|
d4e227286e | ||
|
|
ba705c8c24 | ||
|
|
b6ae4b173e | ||
|
|
23a28be346 | ||
|
|
a0e24dd36f | ||
|
|
a2cde5e17b | ||
|
|
ecc46e9294 | ||
|
|
20b1190d47 | ||
|
|
29b736bcf7 | ||
|
|
a48bc76ca6 | ||
|
|
305c01cdfa | ||
|
|
88bbdf4696 | ||
|
|
afc11279a9 | ||
|
|
a3fb2a84d5 | ||
|
|
4db23e6677 | ||
|
|
5dd36a7969 | ||
|
|
35a3d0027e | ||
|
|
02789ebd86 | ||
|
|
dfd1846b93 | ||
|
|
872205abc6 | ||
|
|
c52cebd20a | ||
|
|
f449b54f87 | ||
|
|
ffcb6e2f6f | ||
|
|
5daa1aa115 | ||
|
|
1dc009f752 | ||
|
|
009b4ff5e7 | ||
|
|
f1a947af92 | ||
|
|
97c098b1ff | ||
|
|
e252cb6643 | ||
|
|
75c0236e1e | ||
|
|
9c4a98bc25 | ||
|
|
9cba11cde5 | ||
|
|
fac5512b04 | ||
|
|
ed9bf05971 | ||
|
|
19d0f3bdc5 | ||
|
|
2abe53de43 | ||
|
|
37a25750d7 | ||
|
|
d3e288447f | ||
|
|
4a44d2668c | ||
|
|
752b1420a3 | ||
|
|
71705fc91f | ||
|
|
645efc7520 | ||
|
|
b6ee0e5219 | ||
|
|
7acf32debc | ||
|
|
13397f68a3 | ||
|
|
79250722d6 | ||
|
|
04b8748a8f | ||
|
|
2dab8053ea | ||
|
|
f8bab2e465 | ||
|
|
46221a8500 | ||
|
|
8b0e61af8c | ||
|
|
2b0a78811a | ||
|
|
5798cd7176 | ||
|
|
5c25637381 | ||
|
|
8316228771 | ||
|
|
695250155e | ||
|
|
545e606c11 | ||
|
|
52771fdb17 | ||
|
|
de631a1052 | ||
|
|
605398db67 | ||
|
|
407c989860 | ||
|
|
9b4b112a97 | ||
|
|
865b75bcbb | ||
|
|
795b0813cc | ||
|
|
3e1f2b8b9d | ||
|
|
1f0d6f0ac7 | ||
|
|
4ab4f4a67c | ||
|
|
5dbdd5e5e4 | ||
|
|
f03cddf674 | ||
|
|
726e908a49 | ||
|
|
043cd673b8 | ||
|
|
f84173e5cc | ||
|
|
bef7ae7f6c | ||
|
|
33aed95a6c | ||
|
|
282317c46e | ||
|
|
2d6a42ac06 | ||
|
|
cd98f72f10 | ||
|
|
29a98f317e | ||
|
|
6334082e6f | ||
|
|
bd4a6a10f9 | ||
|
|
ea4d988082 | ||
|
|
bf8693a7e8 | ||
|
|
32a67c48e0 | ||
|
|
e93f81ca7a | ||
|
|
8f107f5345 | ||
|
|
741046079c | ||
|
|
df7646fd34 | ||
|
|
d350408161 | ||
|
|
bde55a6fe2 | ||
|
|
83c1bed868 | ||
|
|
6845f026bc | ||
|
|
f2c796bcc5 | ||
|
|
a930daf575 | ||
|
|
36d8e5f295 | ||
|
|
71100679a3 | ||
|
|
e3b61b5b1f | ||
|
|
42a5e7422c | ||
|
|
24782950e4 | ||
|
|
e5639102cb | ||
|
|
b74d05603d |
1
.github/workflows/cron_publish_flatpak.yml
vendored
1
.github/workflows/cron_publish_flatpak.yml
vendored
@@ -10,6 +10,7 @@ jobs:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
name: "Check if release is needed"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 180
|
||||
outputs:
|
||||
PCSX2_RELEASE: ${{ steps.getinfo.outputs.PCSX2_RELEASE }}
|
||||
FLATHUB_RELEASE: ${{ steps.getinfo.outputs.FLATHUB_RELEASE }}
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
run: ./.github/workflows/scripts/common/update_base_translation.sh
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@4320041ed380b20e97d388d56a7fb4f9b8c20e79
|
||||
with:
|
||||
title: "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
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@4320041ed380b20e97d388d56a7fb4f9b8c20e79
|
||||
with:
|
||||
title: "PAD: Update to latest controller database"
|
||||
commit-message: "[ci skip] PAD: Update to latest controller database."
|
||||
|
||||
4
.github/workflows/linux_build_matrix.yml
vendored
4
.github/workflows/linux_build_matrix.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "AppImage Build"
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-appimage-sse4"
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-appimage"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
buildAppImage: true
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
uses: ./.github/workflows/linux_build_flatpak.yml
|
||||
with:
|
||||
jobName: "Flatpak Build"
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-flatpak-sse4"
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-flatpak"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
publish: false
|
||||
|
||||
2
.github/workflows/linux_build_qt.yml
vendored
2
.github/workflows/linux_build_qt.yml
vendored
@@ -55,7 +55,7 @@ jobs:
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_COMPRESS: true
|
||||
CCACHE_COMPRESSLEVEL: 9
|
||||
CCACHE_MAXSIZE: 100M
|
||||
CCACHE_MAXSIZE: 500M
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
|
||||
44
.github/workflows/macos_build.yml
vendored
44
.github/workflows/macos_build.yml
vendored
@@ -25,20 +25,26 @@ on:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
sign_and_notarize:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build_macos:
|
||||
name: ${{ inputs.jobName }}
|
||||
runs-on: ${{ inputs.os }}
|
||||
# Set some sort of timeout in the event of run-away builds. We are limited on concurrent jobs so, get rid of them.
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
CCACHE_BASEDIR: ${{ github.workspace }}
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_COMPRESS: true
|
||||
CCACHE_COMPRESSLEVEL: 9
|
||||
CCACHE_MAXSIZE: 100M
|
||||
CCACHE_MAXSIZE: 500M
|
||||
# Only way to use a secret in an if statement
|
||||
SIGN_KEY: ${{ secrets.APPLE_SIGN_P12_B64 }}
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
@@ -143,6 +149,38 @@ jobs:
|
||||
run: make -j$(getconf _NPROCESSORS_ONLN) unittests
|
||||
|
||||
- name: Prepare Build Artifacts
|
||||
run: |
|
||||
mv build/pcsx2*/PCSX2.app PCSX2.app
|
||||
|
||||
- name: Pull the Signing Keys and Notarization Credentials
|
||||
if: ${{ inputs.sign_and_notarize == true && env.SIGN_KEY }}
|
||||
run: |
|
||||
echo "${{ secrets.APPLE_SIGN_P12_B64 }}" | base64 -d > cert.p12
|
||||
echo "${{ secrets.APPLE_APPSTORECONNECT_CFG }}" | base64 -d > key.json
|
||||
|
||||
- name: Sign the Application
|
||||
if: ${{ inputs.sign_and_notarize == true && env.SIGN_KEY }}
|
||||
uses: indygreg/apple-code-sign-action@44d0985b7f4363198e80b6fea63ac3e9dd3e9957
|
||||
with:
|
||||
input_path: 'PCSX2.app'
|
||||
p12_file: cert.p12
|
||||
p12_password: "${{ secrets.APPLE_SIGN_P12_PASS }}"
|
||||
sign_args: |
|
||||
--for-notarization
|
||||
--code-signature-flags=runtime
|
||||
--entitlements-xml-file=pcsx2/Resources/PCSX2.entitlements
|
||||
notarize: true
|
||||
# max_wait_seconds is only present on my fork located at F0bes/apple-code-sign-action@demo4
|
||||
# If we are timing out we should switch to the newest upstream (if I get it upstreamed)
|
||||
# or use my fork.
|
||||
# max_wait_seconds: '2000'
|
||||
staple: true
|
||||
# Generated using rcodesign
|
||||
# Despite what the docs say, I found that this file is required and I had 0 luck
|
||||
# passing the issuer id, key, etc through arguments.
|
||||
app_store_connect_api_key_json_file: 'key.json'
|
||||
|
||||
- name: Zip Build Artifacts
|
||||
run: |
|
||||
TAG="$(git tag --points-at HEAD)"
|
||||
if [ -z "$TAG" ]; then
|
||||
@@ -150,7 +188,7 @@ jobs:
|
||||
else
|
||||
APPNAME="PCSX2-$TAG"
|
||||
fi
|
||||
mv build/pcsx2*/PCSX2.app "$APPNAME.app"
|
||||
mv PCSX2.app "$APPNAME.app"
|
||||
tar --options xz:compression-level=9 -cvJf "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" "$APPNAME.app"
|
||||
mkdir ci-artifacts
|
||||
cp "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" ci-artifacts/macOS.tar.xz
|
||||
|
||||
1
.github/workflows/macos_build_matrix.yml
vendored
1
.github/workflows/macos_build_matrix.yml
vendored
@@ -16,4 +16,5 @@ jobs:
|
||||
with:
|
||||
jobName: "MacOS Build"
|
||||
artifactPrefixName: "PCSX2-macos-Qt"
|
||||
sign_and_notarize: true # If we find that notarization takes a long time we should disable that on PR builds
|
||||
secrets: inherit
|
||||
|
||||
9
.github/workflows/release_cut_new.yml
vendored
9
.github/workflows/release_cut_new.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
# Docs - https://github.com/mathieudutour/github-tag-action
|
||||
- name: Bump Version and Push Tag
|
||||
id: tag_version
|
||||
uses: mathieudutour/github-tag-action@v6.2
|
||||
uses: mathieudutour/github-tag-action@a22cf08638b34d5badda920f9daf6e72c477b07b
|
||||
with:
|
||||
github_token: ${{ github.token }}
|
||||
tag_prefix: v
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
mv ./release-notes.md ${GITHUB_WORKSPACE}/release-notes.md
|
||||
|
||||
- name: Create a GitHub Release (Manual)
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda
|
||||
if: steps.tag_version.outputs.new_tag && github.event_name == 'workflow_dispatch'
|
||||
with:
|
||||
body_path: ./release-notes.md
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
tag_name: ${{ steps.tag_version.outputs.new_tag }}
|
||||
|
||||
- name: Create a GitHub Release (Push)
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda
|
||||
if: steps.tag_version.outputs.new_tag && github.event_name != 'workflow_dispatch'
|
||||
with:
|
||||
body_path: ./release-notes.md
|
||||
@@ -148,6 +148,7 @@ jobs:
|
||||
artifactPrefixName: "PCSX2-macos-Qt"
|
||||
fetchTags: true
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||
sign_and_notarize: true
|
||||
secrets: inherit
|
||||
|
||||
# Upload the Artifacts
|
||||
@@ -204,7 +205,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 22
|
||||
|
||||
- name: Announce Release
|
||||
env:
|
||||
|
||||
13
.github/workflows/scripts/common/kddockwidgets-dodgy-include.patch
vendored
Normal file
13
.github/workflows/scripts/common/kddockwidgets-dodgy-include.patch
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/src/core/indicators/ClassicDropIndicatorOverlay.h b/src/core/indicators/ClassicDropIndicatorOverlay.h
|
||||
index 2dfb9718a..9b01f002e 100644
|
||||
--- a/src/core/indicators/ClassicDropIndicatorOverlay.h
|
||||
+++ b/src/core/indicators/ClassicDropIndicatorOverlay.h
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
-#include "core/DropIndicatorOverlay.h"
|
||||
+#include <kddockwidgets/core/DropIndicatorOverlay.h>
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
25
.github/workflows/scripts/linux/appimage-qt.sh
vendored
25
.github/workflows/scripts/linux/appimage-qt.sh
vendored
@@ -63,9 +63,9 @@ declare -a REMOVE_LIBS=(
|
||||
|
||||
set -e
|
||||
|
||||
LINUXDEPLOY=./linuxdeploy-x86_64
|
||||
LINUXDEPLOY_PLUGIN_QT=./linuxdeploy-plugin-qt-x86_64
|
||||
APPIMAGETOOL=./appimagetool-x86_64
|
||||
LINUXDEPLOY=./linuxdeploy-x86_64.AppImage
|
||||
LINUXDEPLOY_PLUGIN_QT=./linuxdeploy-plugin-qt-x86_64.AppImage
|
||||
APPIMAGETOOL=./appimagetool-x86_64.AppImage
|
||||
PATCHELF=patchelf
|
||||
|
||||
if [ ! -f "$LINUXDEPLOY" ]; then
|
||||
@@ -78,11 +78,8 @@ if [ ! -f "$LINUXDEPLOY_PLUGIN_QT" ]; then
|
||||
chmod +x "$LINUXDEPLOY_PLUGIN_QT"
|
||||
fi
|
||||
|
||||
# Using go-appimage
|
||||
# Backported from https://github.com/stenzek/duckstation/pull/3251
|
||||
if [ ! -f "$APPIMAGETOOL" ]; then
|
||||
APPIMAGETOOLURL=$(wget -q https://api.github.com/repos/probonopd/go-appimage/releases -O - | sed 's/[()",{} ]/\n/g' | grep -o 'https.*continuous.*tool.*86_64.*mage$' | head -1)
|
||||
"$PCSX2DIR/tools/retry.sh" wget -O "$APPIMAGETOOL" "$APPIMAGETOOLURL"
|
||||
"$PCSX2DIR/tools/retry.sh" wget -O "$APPIMAGETOOL" https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
chmod +x "$APPIMAGETOOL"
|
||||
fi
|
||||
|
||||
@@ -190,17 +187,6 @@ echo "Generating AppStream metainfo..."
|
||||
mkdir -p "$OUTDIR/usr/share/metainfo"
|
||||
"$SCRIPTDIR/generate-metainfo.sh" "$OUTDIR/usr/share/metainfo/net.pcsx2.PCSX2.appdata.xml"
|
||||
|
||||
# Copy in AppRun hooks.
|
||||
# Unfortunately linuxdeploy is a bit lame and doesn't let us provide our own AppRun hooks, instead
|
||||
# they have to come from plugins.. and screw writing one of those just to disable Wayland.
|
||||
echo "Copying AppRun hooks..."
|
||||
mkdir -p "$OUTDIR/apprun-hooks"
|
||||
for hookpath in "$SCRIPTDIR/apprun-hooks"/*; do
|
||||
hookname=$(basename "$hookpath")
|
||||
cp -v "$hookpath" "$OUTDIR/apprun-hooks/$hookname"
|
||||
sed -i -e 's/exec /source "$this_dir"\/apprun-hooks\/"'"$hookname"'"\nexec /' "$OUTDIR/AppRun"
|
||||
done
|
||||
|
||||
echo "Generating AppImage..."
|
||||
GIT_VERSION=$(git tag --points-at HEAD)
|
||||
|
||||
@@ -213,5 +199,4 @@ if [[ "${GIT_VERSION}" == "" ]]; then
|
||||
fi
|
||||
|
||||
rm -f "$NAME.AppImage"
|
||||
ARCH=x86_64 VERSION="${GIT_VERSION}" "$APPIMAGETOOL" -s "$OUTDIR" && mv ./*.AppImage "$NAME.AppImage"
|
||||
|
||||
$APPIMAGETOOL -v "$OUTDIR" "$NAME.AppImage"
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
if [[ -z "$I_WANT_A_BROKEN_WAYLAND_UI" ]]; then
|
||||
echo "Forcing X11 instead of Wayland, due to various protocol limitations"
|
||||
echo "and Qt issues. If you want to use Wayland, launch PCSX2 with"
|
||||
echo "I_WANT_A_BROKEN_WAYLAND_UI=YES set."
|
||||
export QT_QPA_PLATFORM=xcb
|
||||
else
|
||||
echo "Wayland is not being disabled. Do not complain when things break."
|
||||
fi
|
||||
|
||||
@@ -15,13 +15,14 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
|
||||
fi
|
||||
|
||||
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
|
||||
LIBJPEG=9f
|
||||
LIBJPEGTURBO=3.1.0
|
||||
LIBPNG=1.6.45
|
||||
LIBWEBP=1.5.0
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
SDL=SDL2-2.30.11
|
||||
QT=6.8.1
|
||||
ZSTD=1.5.6
|
||||
SDL=SDL3-3.2.8
|
||||
QT=6.8.2
|
||||
ZSTD=1.5.7
|
||||
KDDOCKWIDGETS=2.2.1
|
||||
|
||||
SHADERC=2024.1
|
||||
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -33,27 +34,28 @@ cd deps-build
|
||||
|
||||
cat > SHASUMS <<EOF
|
||||
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
|
||||
04705c110cb2469caa79fb71fba3d7bf834914706e9641a4589485c1f832565b jpegsrc.v$LIBJPEG.tar.gz
|
||||
9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
|
||||
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f $SDL.tar.gz
|
||||
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
|
||||
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
|
||||
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
|
||||
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
|
||||
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
|
||||
2226fbde4e2ddd12f8bf4b239c8f38fd706a54e789e63467dfddc77129eca203 qtwayland-everywhere-src-$QT.tar.xz
|
||||
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 $SDL.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05 qtbase-everywhere-src-$QT.tar.xz
|
||||
d2a1bbb84707b8a0aec29227b170be00f04383fbf2361943596d09e7e443c8e1 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
aa2579f21ca66d19cbcf31d87e9067e07932635d36869c8239d4decd0a9dc1fa qtsvg-everywhere-src-$QT.tar.xz
|
||||
326381b7d43f07913612f291abc298ae79bd95382e2233abce982cff2b53d2c0 qttools-everywhere-src-$QT.tar.xz
|
||||
d2106e8a580bfd77702c4c1840299288d344902b0e2c758ca813ea04c6d6a3d1 qttranslations-everywhere-src-$QT.tar.xz
|
||||
5e46157908295f2bf924462d8c0855b0508ba338ced9e810891fefa295dc9647 qtwayland-everywhere-src-$QT.tar.xz
|
||||
eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADERC.tar.gz
|
||||
aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697 shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||
03ee1a2c06f3b61008478f4abe9423454e53e580b9488b47c8071547c6a9db47 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||
8693e06abee0c88517d8480b22647702a51a0708f3c876ed5385d9a4e356e1a5 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
EOF
|
||||
|
||||
curl -L \
|
||||
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.zip" \
|
||||
-O "https://ijg.org/files/jpegsrc.v$LIBJPEG.tar.gz" \
|
||||
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
|
||||
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
|
||||
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
|
||||
-O "https://github.com/lz4/lz4/archive/$LZ4.tar.gz" \
|
||||
@@ -68,7 +70,8 @@ curl -L \
|
||||
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
|
||||
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
|
||||
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
|
||||
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz"
|
||||
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
|
||||
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz"
|
||||
|
||||
shasum -a 256 --check SHASUMS
|
||||
|
||||
@@ -90,16 +93,14 @@ cmake --build build --parallel
|
||||
ninja -C build install
|
||||
cd ..
|
||||
|
||||
echo "Building libjpeg..."
|
||||
rm -fr "jpeg-$LIBJPEG"
|
||||
tar xf "jpegsrc.v$LIBJPEG.tar.gz"
|
||||
cd "jpeg-$LIBJPEG"
|
||||
mkdir build
|
||||
cd build
|
||||
../configure --prefix="$INSTALLDIR" --disable-static --enable-shared
|
||||
make "-j$NPROCS"
|
||||
make install
|
||||
cd ../..
|
||||
echo "Building libjpegturbo..."
|
||||
rm -fr "libjpeg-turbo-$LIBJPEGTURBO"
|
||||
tar xf "libjpeg-turbo-$LIBJPEGTURBO.tar.gz"
|
||||
cd "libjpeg-turbo-$LIBJPEGTURBO"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DENABLE_STATIC=OFF -DENABLE_SHARED=ON -B build -G Ninja
|
||||
cmake --build build --parallel
|
||||
ninja -C build install
|
||||
cd ..
|
||||
|
||||
echo "Building LZ4..."
|
||||
rm -fr "lz4-$LZ4"
|
||||
@@ -233,6 +234,16 @@ cmake --build . --parallel
|
||||
ninja install
|
||||
cd ../../
|
||||
|
||||
echo "Building KDDockWidgets..."
|
||||
rm -fr "KDDockWidgets-$KDDOCKWIDGETS"
|
||||
tar xf "KDDockWidgets-$KDDOCKWIDGETS.tar.gz"
|
||||
cd "KDDockWidgets-$KDDOCKWIDGETS"
|
||||
patch -p1 < "$SCRIPTDIR/../common/kddockwidgets-dodgy-include.patch"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DKDDockWidgets_QT6=true -DKDDockWidgets_EXAMPLES=false -DKDDockWidgets_FRONTENDS=qtwidgets -B build -G Ninja
|
||||
cmake --build build --parallel
|
||||
ninja -C build install
|
||||
cd ..
|
||||
|
||||
echo "Building shaderc..."
|
||||
rm -fr "shaderc-$SHADERC"
|
||||
tar xf "shaderc-$SHADERC.tar.gz"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "sdl2",
|
||||
"name": "sdl3",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
@@ -14,8 +14,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://libsdl.org/release/SDL2-2.30.11.tar.gz",
|
||||
"sha256": "8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f"
|
||||
"url": "https://libsdl.org/release/SDL3-3.2.8.tar.gz",
|
||||
"sha256": "13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
32
.github/workflows/scripts/linux/flatpak/modules/23-kddockwidgets.json
vendored
Normal file
32
.github/workflows/scripts/linux/flatpak/modules/23-kddockwidgets.json
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "kddockwidgets",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
"-DKDDockWidgets_QT6=true",
|
||||
"-DKDDockWidgets_EXAMPLES=false",
|
||||
"-DKDDockWidgets_FRONTENDS=qtwidgets"
|
||||
],
|
||||
"build-options": {
|
||||
"strip": true
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/KDAB/KDDockWidgets.git",
|
||||
"tag": "v2.2.1",
|
||||
"commit": "3aaccddc00a11a643e0959a24677838993de15ac",
|
||||
"disable-submodules": true
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "../../../common/kddockwidgets-dodgy-include.patch"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
"/share/doc/KDDockWidgets-qt6",
|
||||
"/mkspecs/modules/qt_KDDockWidgets.pri",
|
||||
"/lib/cmake",
|
||||
"/include"
|
||||
]
|
||||
}
|
||||
@@ -19,16 +19,17 @@
|
||||
"--device=all",
|
||||
"--share=network",
|
||||
"--share=ipc",
|
||||
"--socket=x11",
|
||||
"--socket=wayland",
|
||||
"--socket=fallback-x11",
|
||||
"--socket=pulseaudio",
|
||||
"--talk-name=org.freedesktop.ScreenSaver",
|
||||
"--env=QT_QPA_PLATFORM=xcb"
|
||||
"--talk-name=org.freedesktop.ScreenSaver"
|
||||
],
|
||||
"modules": [
|
||||
"modules/10-libpcap.json",
|
||||
"modules/20-sdl2.json",
|
||||
"modules/20-sdl3.json",
|
||||
"modules/21-libbacktrace.json",
|
||||
"modules/22-shaderc.json",
|
||||
"modules/23-kddockwidgets.json",
|
||||
{
|
||||
"name": "pcsx2",
|
||||
"buildsystem": "cmake-ninja",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 133 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 2.3 MiB |
@@ -6,17 +6,21 @@
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0+</project_license>
|
||||
<name>PCSX2</name>
|
||||
<developer_name>PCSX2</developer_name>
|
||||
<summary>PlayStation 2 Emulator</summary>
|
||||
<developer id="net.pcsx2">
|
||||
<name>PCSX2 Team</name>
|
||||
</developer>
|
||||
<summary>PlayStation 2 emulator</summary>
|
||||
<description>
|
||||
<p>PCSX2 is a free and open-source PlayStation 2 (PS2) emulator. Its purpose is to emulate the PS2's hardware, using a combination of MIPS CPU Interpreters, Recompilers, and a Virtual Machine which manages hardware states and PS2 system memory. This allows you to play PS2 games on your PC, with many additional features and benefits.</p>
|
||||
<p>PlayStation 2 and PS2 are registered trademarks of Sony Interactive Entertainment. This application is not affiliated in any way with Sony Interactive Entertainment.</p>
|
||||
</description>
|
||||
<url type="homepage">https://pcsx2.net/</url>
|
||||
<url type="vcs-browser">https://github.com/PCSX2/pcsx2</url>
|
||||
<url type="bugtracker">https://github.com/PCSX2/pcsx2/issues</url>
|
||||
<url type="donation">https://github.com/sponsors/PCSX2</url>
|
||||
<url type="faq">https://pcsx2.net/docs/</url>
|
||||
<url type="help">https://pcsx2.net/discord</url>
|
||||
<url type="contribute">https://github.com/PCSX2/pcsx2/blob/master/.github/CONTRIBUTING.md</url>
|
||||
<url type="translate">https://crowdin.com/project/pcsx2-emulator</url>
|
||||
<url type="contact">https://mastodon.social/@PCSX2</url>
|
||||
<screenshots>
|
||||
@@ -37,6 +41,26 @@
|
||||
</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<categories>
|
||||
<category>Game</category>
|
||||
<category>Emulator</category>
|
||||
</categories>
|
||||
<branding>
|
||||
<color type="primary" scheme_preference="light">#3584e4</color>
|
||||
<color type="primary" scheme_preference="dark">#241f31</color>
|
||||
</branding>
|
||||
<supports>
|
||||
<control>keyboard</control>
|
||||
<control>pointing</control>
|
||||
<internet>offline-only</internet>
|
||||
</supports>
|
||||
<recommends>
|
||||
<control>gamepad</control>
|
||||
<memory>8192</memory>
|
||||
</recommends>
|
||||
<requires>
|
||||
<display_length compare="ge">768</display_length>
|
||||
</requires>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<update_contact>pcsx2_AT_pcsx2.net</update_contact>
|
||||
<releases>
|
||||
|
||||
@@ -40,15 +40,16 @@ fi
|
||||
|
||||
FREETYPE=2.13.3
|
||||
HARFBUZZ=10.0.1
|
||||
SDL=SDL2-2.30.11
|
||||
ZSTD=1.5.6
|
||||
SDL=SDL3-3.2.8
|
||||
ZSTD=1.5.7
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
LIBPNG=1.6.45
|
||||
LIBJPEG=9f
|
||||
LIBJPEGTURBO=3.1.0
|
||||
LIBWEBP=1.5.0
|
||||
FFMPEG=6.0
|
||||
MOLTENVK=1.2.9
|
||||
QT=6.7.2
|
||||
QT=6.7.3
|
||||
KDDOCKWIDGETS=2.2.1
|
||||
|
||||
SHADERC=2024.1
|
||||
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -76,23 +77,24 @@ CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
|
||||
cat > SHASUMS <<EOF
|
||||
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
|
||||
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
|
||||
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f $SDL.tar.gz
|
||||
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
|
||||
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 $SDL.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
|
||||
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
|
||||
04705c110cb2469caa79fb71fba3d7bf834914706e9641a4589485c1f832565b jpegsrc.v$LIBJPEG.tar.gz
|
||||
9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||
57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082 ffmpeg-$FFMPEG.tar.xz
|
||||
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
|
||||
c5f22a5e10fb162895ded7de0963328e7307611c688487b5d152c9ee64767599 qtbase-everywhere-src-$QT.tar.xz
|
||||
e1a1d8785fae67d16ad0a443b01d5f32663a6b68d275f1806ebab257485ce5d6 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
fb0d1286a35be3583fee34aeb5843c94719e07193bdf1d4d8b0dc14009caef01 qtsvg-everywhere-src-$QT.tar.xz
|
||||
58e855ad1b2533094726c8a425766b63a04a0eede2ed85086860e54593aa4b2a qttools-everywhere-src-$QT.tar.xz
|
||||
9845780b5dc1b7279d57836db51aeaf2e4a1160c42be09750616f39157582ca9 qttranslations-everywhere-src-$QT.tar.xz
|
||||
8ccbb9ab055205ac76632c9eeddd1ed6fc66936fc56afc2ed0fd5d9e23da3097 qtbase-everywhere-src-$QT.tar.xz
|
||||
9fd58144081654c3373768dd96ead294023830927b14fe3d3c1ef641fb324753 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
40142cb71fb1e07ad612bc361b67f5d54cd9367f9979ae6b86124a064deda06b qtsvg-everywhere-src-$QT.tar.xz
|
||||
f03bb7df619cd9ac9dba110e30b7bcab5dd88eb8bdc9cc752563b4367233203f qttools-everywhere-src-$QT.tar.xz
|
||||
dcc762acac043b9bb5e4d369b6d6f53e0ecfcf76a408fe0db5f7ef071c9d6dc8 qttranslations-everywhere-src-$QT.tar.xz
|
||||
eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADERC.tar.gz
|
||||
aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697 shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||
03ee1a2c06f3b61008478f4abe9423454e53e580b9488b47c8071547c6a9db47 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||
8693e06abee0c88517d8480b22647702a51a0708f3c876ed5385d9a4e356e1a5 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
EOF
|
||||
|
||||
curl -C - -L \
|
||||
@@ -102,7 +104,7 @@ curl -C - -L \
|
||||
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
|
||||
-O "https://github.com/lz4/lz4/archive/$LZ4.tar.gz" \
|
||||
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
|
||||
-O "https://ijg.org/files/jpegsrc.v$LIBJPEG.tar.gz" \
|
||||
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
|
||||
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
|
||||
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
|
||||
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
|
||||
@@ -114,7 +116,8 @@ curl -C - -L \
|
||||
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
|
||||
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
|
||||
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
|
||||
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz"
|
||||
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
|
||||
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz"
|
||||
|
||||
shasum -a 256 --check SHASUMS
|
||||
|
||||
@@ -200,21 +203,12 @@ merge_binaries $(realpath build) $(realpath build-arm64)
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Installing libjpeg..."
|
||||
rm -fr "jpeg-$LIBJPEG"
|
||||
tar xf "jpegsrc.v$LIBJPEG.tar.gz"
|
||||
cd "jpeg-$LIBJPEG"
|
||||
mkdir build
|
||||
cd build
|
||||
../configure --prefix="$INSTALLDIR" --disable-static --enable-shared --host="x86_64-apple-darwin" CFLAGS="-arch x86_64"
|
||||
make "-j$NPROCS"
|
||||
cd ..
|
||||
mkdir build-arm64
|
||||
cd build-arm64
|
||||
../configure --prefix="$INSTALLDIR" --disable-static --enable-shared --host="aarch64-apple-darwin" CFLAGS="-arch arm64"
|
||||
make "-j$NPROCS"
|
||||
cd ..
|
||||
merge_binaries $(realpath build) $(realpath build-arm64)
|
||||
echo "Installing libjpegturbo..."
|
||||
rm -fr "libjpeg-turbo-$LIBJPEGTURBO"
|
||||
tar xf "libjpeg-turbo-$LIBJPEGTURBO.tar.gz"
|
||||
cd "libjpeg-turbo-$LIBJPEGTURBO"
|
||||
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_ARM64" -DENABLE_STATIC=OFF -DENABLE_SHARED=ON -B build-arm64
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
@@ -366,6 +360,16 @@ make "-j$NPROCS"
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
echo "Building KDDockWidgets..."
|
||||
rm -fr "KDDockWidgets-$KDDOCKWIDGETS"
|
||||
tar xf "KDDockWidgets-$KDDOCKWIDGETS.tar.gz"
|
||||
cd "KDDockWidgets-$KDDOCKWIDGETS"
|
||||
patch -p1 < "$SCRIPTDIR/../common/kddockwidgets-dodgy-include.patch"
|
||||
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DKDDockWidgets_QT6=true -DKDDockWidgets_EXAMPLES=false -DKDDockWidgets_FRONTENDS=qtwidgets -B build
|
||||
cmake --build build --parallel
|
||||
cmake --install build
|
||||
cd ..
|
||||
|
||||
echo "Cleaning up..."
|
||||
cd ..
|
||||
rm -rf deps-build
|
||||
|
||||
@@ -22,15 +22,16 @@ fi
|
||||
|
||||
FREETYPE=2.13.3
|
||||
HARFBUZZ=10.0.1
|
||||
SDL=SDL2-2.30.11
|
||||
ZSTD=1.5.6
|
||||
SDL=SDL3-3.2.8
|
||||
ZSTD=1.5.7
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
LIBPNG=1.6.45
|
||||
LIBJPEG=9f
|
||||
LIBJPEGTURBO=3.1.0
|
||||
LIBWEBP=1.5.0
|
||||
FFMPEG=6.0
|
||||
MOLTENVK=1.2.9
|
||||
QT=6.7.2
|
||||
QT=6.7.3
|
||||
KDDOCKWIDGETS=2.2.1
|
||||
|
||||
SHADERC=2024.1
|
||||
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -56,23 +57,24 @@ CMAKE_COMMON=(
|
||||
cat > SHASUMS <<EOF
|
||||
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
|
||||
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
|
||||
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f $SDL.tar.gz
|
||||
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
|
||||
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 $SDL.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
|
||||
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
|
||||
04705c110cb2469caa79fb71fba3d7bf834914706e9641a4589485c1f832565b jpegsrc.v$LIBJPEG.tar.gz
|
||||
9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||
57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082 ffmpeg-$FFMPEG.tar.xz
|
||||
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
|
||||
c5f22a5e10fb162895ded7de0963328e7307611c688487b5d152c9ee64767599 qtbase-everywhere-src-$QT.tar.xz
|
||||
e1a1d8785fae67d16ad0a443b01d5f32663a6b68d275f1806ebab257485ce5d6 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
fb0d1286a35be3583fee34aeb5843c94719e07193bdf1d4d8b0dc14009caef01 qtsvg-everywhere-src-$QT.tar.xz
|
||||
58e855ad1b2533094726c8a425766b63a04a0eede2ed85086860e54593aa4b2a qttools-everywhere-src-$QT.tar.xz
|
||||
9845780b5dc1b7279d57836db51aeaf2e4a1160c42be09750616f39157582ca9 qttranslations-everywhere-src-$QT.tar.xz
|
||||
8ccbb9ab055205ac76632c9eeddd1ed6fc66936fc56afc2ed0fd5d9e23da3097 qtbase-everywhere-src-$QT.tar.xz
|
||||
9fd58144081654c3373768dd96ead294023830927b14fe3d3c1ef641fb324753 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
40142cb71fb1e07ad612bc361b67f5d54cd9367f9979ae6b86124a064deda06b qtsvg-everywhere-src-$QT.tar.xz
|
||||
f03bb7df619cd9ac9dba110e30b7bcab5dd88eb8bdc9cc752563b4367233203f qttools-everywhere-src-$QT.tar.xz
|
||||
dcc762acac043b9bb5e4d369b6d6f53e0ecfcf76a408fe0db5f7ef071c9d6dc8 qttranslations-everywhere-src-$QT.tar.xz
|
||||
eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADERC.tar.gz
|
||||
aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697 shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||
03ee1a2c06f3b61008478f4abe9423454e53e580b9488b47c8071547c6a9db47 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||
8693e06abee0c88517d8480b22647702a51a0708f3c876ed5385d9a4e356e1a5 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
EOF
|
||||
|
||||
curl -L \
|
||||
@@ -82,7 +84,7 @@ curl -L \
|
||||
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
|
||||
-O "https://github.com/lz4/lz4/archive/$LZ4.tar.gz" \
|
||||
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
|
||||
-O "https://ijg.org/files/jpegsrc.v$LIBJPEG.tar.gz" \
|
||||
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
|
||||
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
|
||||
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
|
||||
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
|
||||
@@ -94,7 +96,8 @@ curl -L \
|
||||
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
|
||||
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
|
||||
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
|
||||
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz"
|
||||
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
|
||||
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz"
|
||||
|
||||
shasum -a 256 --check SHASUMS
|
||||
|
||||
@@ -153,16 +156,14 @@ make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Installing libjpeg..."
|
||||
rm -fr "jpeg-$LIBJPEG"
|
||||
tar xf "jpegsrc.v$LIBJPEG.tar.gz"
|
||||
cd "jpeg-$LIBJPEG"
|
||||
mkdir build
|
||||
cd build
|
||||
../configure --prefix="$INSTALLDIR" --disable-static --enable-shared --host="x86_64-apple-darwin" CFLAGS="-arch x86_64"
|
||||
make "-j$NPROCS"
|
||||
make install
|
||||
cd ../..
|
||||
echo "Installing libjpegturbo..."
|
||||
rm -fr "libjpeg-turbo-$LIBJPEGTURBO"
|
||||
tar xf "libjpeg-turbo-$LIBJPEGTURBO.tar.gz"
|
||||
cd "libjpeg-turbo-$LIBJPEGTURBO"
|
||||
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_X64" -DENABLE_STATIC=OFF -DENABLE_SHARED=ON -B build
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Installing WebP..."
|
||||
rm -fr "libwebp-$LIBWEBP"
|
||||
@@ -180,8 +181,8 @@ rm -fr "freetype-$FREETYPE"
|
||||
tar xf "freetype-$FREETYPE.tar.xz"
|
||||
cd "freetype-$FREETYPE"
|
||||
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_DISABLE_HARFBUZZ=TRUE -B build
|
||||
cmake --build build --parallel
|
||||
cmake --install build
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Building HarfBuzz..."
|
||||
@@ -189,8 +190,8 @@ rm -fr "harfbuzz-$HARFBUZZ"
|
||||
tar xf "harfbuzz-$HARFBUZZ.tar.gz"
|
||||
cd "harfbuzz-$HARFBUZZ"
|
||||
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DHB_BUILD_UTILS=OFF -B build
|
||||
cmake --build build --parallel
|
||||
cmake --install build
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Building FreeType with HarfBuzz..."
|
||||
@@ -198,8 +199,8 @@ rm -fr "freetype-$FREETYPE"
|
||||
tar xf "freetype-$FREETYPE.tar.xz"
|
||||
cd "freetype-$FREETYPE"
|
||||
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_REQUIRE_HARFBUZZ=TRUE -B build
|
||||
cmake --build build --parallel
|
||||
cmake --install build
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
# MoltenVK already builds universal binaries, nothing special to do here.
|
||||
@@ -324,6 +325,16 @@ make "-j$NPROCS"
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
echo "Building KDDockWidgets..."
|
||||
rm -fr "KDDockWidgets-$KDDOCKWIDGETS"
|
||||
tar xf "KDDockWidgets-$KDDOCKWIDGETS.tar.gz"
|
||||
cd "KDDockWidgets-$KDDOCKWIDGETS"
|
||||
patch -p1 < "$SCRIPTDIR/../common/kddockwidgets-dodgy-include.patch"
|
||||
cmake "${CMAKE_COMMON[@]}" -DKDDockWidgets_QT6=true -DKDDockWidgets_EXAMPLES=false -DKDDockWidgets_FRONTENDS=qtwidgets -B build
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Cleaning up..."
|
||||
cd ..
|
||||
rm -rf deps-build
|
||||
|
||||
640
.github/workflows/scripts/releases/announce-release/package-lock.json
generated
vendored
640
.github/workflows/scripts/releases/announce-release/package-lock.json
generated
vendored
@@ -10,8 +10,8 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
"@octokit/plugin-throttling": "^3.5.2",
|
||||
"@octokit/rest": "^18.12.0",
|
||||
"@octokit/plugin-throttling": "^9.4.0",
|
||||
"@octokit/rest": "^21.1.1",
|
||||
"discord.js": "^13.2.0"
|
||||
}
|
||||
},
|
||||
@@ -61,45 +61,102 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
|
||||
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz",
|
||||
"integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz",
|
||||
"integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==",
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.4.tgz",
|
||||
"integrity": "sha512-lAS9k7d6I0MPN+gb9bKDt7X8SdxknYqAMh44S5L+lNqIN2NuV8nvv3g8rPp7MuRxcOpxpUIATWprO0C34a8Qmg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/request-error": "^2.0.5",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
"@octokit/auth-token": "^5.0.0",
|
||||
"@octokit/graphql": "^8.1.2",
|
||||
"@octokit/request": "^9.2.1",
|
||||
"@octokit/request-error": "^6.1.7",
|
||||
"@octokit/types": "^13.6.2",
|
||||
"before-after-hook": "^3.0.2",
|
||||
"universal-user-agent": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core/node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/core/node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "6.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
|
||||
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
|
||||
"version": "10.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.3.tgz",
|
||||
"integrity": "sha512-nBRBMpKPhQUxCsQQeW+rCJ/OPSMcj3g0nfHn01zGYZXuNDvvXudF/TYY6APj5THlurerpFN4a/dQAIAaM6BYhA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
"@octokit/types": "^13.6.2",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/endpoint/node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
|
||||
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
|
||||
"version": "8.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.1.tgz",
|
||||
"integrity": "sha512-n57hXtOoHrhwTWdvhVkdJHdhTv0JstjDbDRhJfwIRNfFqmSo1DaK/mD2syoNUoLCyqSjBpGAKOG0BuwF392slw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
"@octokit/request": "^9.2.2",
|
||||
"@octokit/types": "^13.8.0",
|
||||
"universal-user-agent": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql/node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/graphql/node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
@@ -108,28 +165,75 @@
|
||||
"integrity": "sha512-dWZfYvCCdjZzDYA3lIAMF72Q0jld8xidqCq5Ryw09eBJXZdcM6he0vWBTvw/b5UnGYqexxOyHWgfrsTlUJL3Gw=="
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest": {
|
||||
"version": "2.16.9",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.9.tgz",
|
||||
"integrity": "sha512-gfSCMgz5scFKsR0dW4jaYsDJVt/UwCHp4dF7sHlmSekZvwzvLiOAGZ4MQkEsL5DW9hIk2W+UQkYZMTA1b6Wsqw==",
|
||||
"version": "11.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.2.tgz",
|
||||
"integrity": "sha512-BXJ7XPCTDXFF+wxcg/zscfgw2O/iDPtNSkwwR1W1W5c4Mb3zav/M2XvxQ23nVmKj7jpweB4g8viMeCQdm7LMVA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.33.0"
|
||||
"@octokit/types": "^13.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-request-log": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
|
||||
"integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-5.3.1.tgz",
|
||||
"integrity": "sha512-n/lNeCtq+9ofhC15xzmJCNKP2BWTv8Ih2TTy+jatNCCq/gQP/V7rK3fjIfuz0pDWDALO/o/4QY4hyOF6TQQFUw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=3"
|
||||
"@octokit/core": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.12.1.tgz",
|
||||
"integrity": "sha512-0nY3htfl6x9UkPcqv8pm9vOC/bTA7f4IMDWln13neHRdNWQvOQgZ9fRxK7BAc74rye4yVINEFi9Yb9rnGUvosA==",
|
||||
"version": "13.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.1.tgz",
|
||||
"integrity": "sha512-o8uOBdsyR+WR8MK9Cco8dCgvG13H1RlM1nWnK/W7TEACQBFux/vPREgKucxUfuDQ5yi1T3hGf4C5ZmZXAERgwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.33.0",
|
||||
"deprecation": "^2.3.1"
|
||||
"@octokit/types": "^13.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-retry": {
|
||||
@@ -142,49 +246,107 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-throttling": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-3.7.0.tgz",
|
||||
"integrity": "sha512-qrKT1Yl/KuwGSC6/oHpLBot3ooC9rq0/ryDYBCpkRtoj+R8T47xTMDT6Tk2CxWopFota/8Pi/2SqArqwC0JPow==",
|
||||
"version": "9.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.4.0.tgz",
|
||||
"integrity": "sha512-IOlXxXhZA4Z3m0EEYtrrACkuHiArHLZ3CvqWwOez/pURNqRuwfoFlTPbN5Muf28pzFuztxPyiUiNwz8KctdZaQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.1",
|
||||
"@octokit/types": "^13.7.0",
|
||||
"bottleneck": "^2.15.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": "^3.5.0"
|
||||
"@octokit/core": "^6.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-throttling/node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/plugin-throttling/node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.2.tgz",
|
||||
"integrity": "sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA==",
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.2.tgz",
|
||||
"integrity": "sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
"@octokit/endpoint": "^10.1.3",
|
||||
"@octokit/request-error": "^6.1.7",
|
||||
"@octokit/types": "^13.6.2",
|
||||
"fast-content-type-parse": "^2.0.0",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
||||
"version": "6.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.7.tgz",
|
||||
"integrity": "sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
"@octokit/types": "^13.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/request-error/node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request/node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/request/node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest": {
|
||||
"version": "18.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz",
|
||||
"integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==",
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-21.1.1.tgz",
|
||||
"integrity": "sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/core": "^3.5.1",
|
||||
"@octokit/plugin-paginate-rest": "^2.16.8",
|
||||
"@octokit/plugin-request-log": "^1.0.4",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^5.12.0"
|
||||
"@octokit/core": "^6.1.4",
|
||||
"@octokit/plugin-paginate-rest": "^11.4.2",
|
||||
"@octokit/plugin-request-log": "^5.3.1",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^13.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
@@ -234,9 +396,10 @@
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
|
||||
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz",
|
||||
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/bottleneck": {
|
||||
"version": "2.19.5",
|
||||
@@ -270,11 +433,6 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
},
|
||||
"node_modules/discord-api-types": {
|
||||
"version": "0.23.1",
|
||||
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.23.1.tgz",
|
||||
@@ -316,6 +474,22 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-content-type-parse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz",
|
||||
"integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-obj": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
|
||||
@@ -324,14 +498,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
@@ -375,14 +541,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/ow": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz",
|
||||
@@ -429,9 +587,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/vali-date": {
|
||||
"version": "1.0.0",
|
||||
@@ -455,11 +614,6 @@
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
@@ -517,45 +671,86 @@
|
||||
}
|
||||
},
|
||||
"@octokit/auth-token": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
|
||||
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
}
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz",
|
||||
"integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw=="
|
||||
},
|
||||
"@octokit/core": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz",
|
||||
"integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==",
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.4.tgz",
|
||||
"integrity": "sha512-lAS9k7d6I0MPN+gb9bKDt7X8SdxknYqAMh44S5L+lNqIN2NuV8nvv3g8rPp7MuRxcOpxpUIATWprO0C34a8Qmg==",
|
||||
"requires": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/request-error": "^2.0.5",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
"@octokit/auth-token": "^5.0.0",
|
||||
"@octokit/graphql": "^8.1.2",
|
||||
"@octokit/request": "^9.2.1",
|
||||
"@octokit/request-error": "^6.1.7",
|
||||
"@octokit/types": "^13.6.2",
|
||||
"before-after-hook": "^3.0.2",
|
||||
"universal-user-agent": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g=="
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/endpoint": {
|
||||
"version": "6.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
|
||||
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
|
||||
"version": "10.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.3.tgz",
|
||||
"integrity": "sha512-nBRBMpKPhQUxCsQQeW+rCJ/OPSMcj3g0nfHn01zGYZXuNDvvXudF/TYY6APj5THlurerpFN4a/dQAIAaM6BYhA==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
"@octokit/types": "^13.6.2",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g=="
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/graphql": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
|
||||
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
|
||||
"version": "8.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.1.tgz",
|
||||
"integrity": "sha512-n57hXtOoHrhwTWdvhVkdJHdhTv0JstjDbDRhJfwIRNfFqmSo1DaK/mD2syoNUoLCyqSjBpGAKOG0BuwF392slw==",
|
||||
"requires": {
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
"@octokit/request": "^9.2.2",
|
||||
"@octokit/types": "^13.8.0",
|
||||
"universal-user-agent": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g=="
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
@@ -564,26 +759,55 @@
|
||||
"integrity": "sha512-dWZfYvCCdjZzDYA3lIAMF72Q0jld8xidqCq5Ryw09eBJXZdcM6he0vWBTvw/b5UnGYqexxOyHWgfrsTlUJL3Gw=="
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
"version": "2.16.9",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.9.tgz",
|
||||
"integrity": "sha512-gfSCMgz5scFKsR0dW4jaYsDJVt/UwCHp4dF7sHlmSekZvwzvLiOAGZ4MQkEsL5DW9hIk2W+UQkYZMTA1b6Wsqw==",
|
||||
"version": "11.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.2.tgz",
|
||||
"integrity": "sha512-BXJ7XPCTDXFF+wxcg/zscfgw2O/iDPtNSkwwR1W1W5c4Mb3zav/M2XvxQ23nVmKj7jpweB4g8viMeCQdm7LMVA==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.33.0"
|
||||
"@octokit/types": "^13.7.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g=="
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-request-log": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
|
||||
"integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-5.3.1.tgz",
|
||||
"integrity": "sha512-n/lNeCtq+9ofhC15xzmJCNKP2BWTv8Ih2TTy+jatNCCq/gQP/V7rK3fjIfuz0pDWDALO/o/4QY4hyOF6TQQFUw==",
|
||||
"requires": {}
|
||||
},
|
||||
"@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.12.1.tgz",
|
||||
"integrity": "sha512-0nY3htfl6x9UkPcqv8pm9vOC/bTA7f4IMDWln13neHRdNWQvOQgZ9fRxK7BAc74rye4yVINEFi9Yb9rnGUvosA==",
|
||||
"version": "13.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.1.tgz",
|
||||
"integrity": "sha512-o8uOBdsyR+WR8MK9Cco8dCgvG13H1RlM1nWnK/W7TEACQBFux/vPREgKucxUfuDQ5yi1T3hGf4C5ZmZXAERgwQ==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.33.0",
|
||||
"deprecation": "^2.3.1"
|
||||
"@octokit/types": "^13.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g=="
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-retry": {
|
||||
@@ -596,46 +820,88 @@
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-throttling": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-3.7.0.tgz",
|
||||
"integrity": "sha512-qrKT1Yl/KuwGSC6/oHpLBot3ooC9rq0/ryDYBCpkRtoj+R8T47xTMDT6Tk2CxWopFota/8Pi/2SqArqwC0JPow==",
|
||||
"version": "9.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.4.0.tgz",
|
||||
"integrity": "sha512-IOlXxXhZA4Z3m0EEYtrrACkuHiArHLZ3CvqWwOez/pURNqRuwfoFlTPbN5Muf28pzFuztxPyiUiNwz8KctdZaQ==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.1",
|
||||
"@octokit/types": "^13.7.0",
|
||||
"bottleneck": "^2.15.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g=="
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/request": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.2.tgz",
|
||||
"integrity": "sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA==",
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.2.tgz",
|
||||
"integrity": "sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg==",
|
||||
"requires": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
"@octokit/endpoint": "^10.1.3",
|
||||
"@octokit/request-error": "^6.1.7",
|
||||
"@octokit/types": "^13.6.2",
|
||||
"fast-content-type-parse": "^2.0.0",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g=="
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
||||
"version": "6.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.7.tgz",
|
||||
"integrity": "sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
"@octokit/types": "^13.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g=="
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/rest": {
|
||||
"version": "18.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz",
|
||||
"integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==",
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-21.1.1.tgz",
|
||||
"integrity": "sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg==",
|
||||
"requires": {
|
||||
"@octokit/core": "^3.5.1",
|
||||
"@octokit/plugin-paginate-rest": "^2.16.8",
|
||||
"@octokit/plugin-request-log": "^1.0.4",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^5.12.0"
|
||||
"@octokit/core": "^6.1.4",
|
||||
"@octokit/plugin-paginate-rest": "^11.4.2",
|
||||
"@octokit/plugin-request-log": "^5.3.1",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^13.3.0"
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
@@ -675,9 +941,9 @@
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"before-after-hook": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
|
||||
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz",
|
||||
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A=="
|
||||
},
|
||||
"bottleneck": {
|
||||
"version": "2.19.5",
|
||||
@@ -702,11 +968,6 @@
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
},
|
||||
"discord-api-types": {
|
||||
"version": "0.23.1",
|
||||
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.23.1.tgz",
|
||||
@@ -735,16 +996,16 @@
|
||||
"is-obj": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"fast-content-type-parse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz",
|
||||
"integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q=="
|
||||
},
|
||||
"is-obj": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
|
||||
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="
|
||||
},
|
||||
"is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
},
|
||||
"lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
@@ -771,14 +1032,6 @@
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"ow": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz",
|
||||
@@ -813,9 +1066,9 @@
|
||||
"integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA=="
|
||||
},
|
||||
"universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q=="
|
||||
},
|
||||
"vali-date": {
|
||||
"version": "1.0.0",
|
||||
@@ -836,11 +1089,6 @@
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
"@octokit/plugin-throttling": "^3.5.2",
|
||||
"@octokit/rest": "^18.12.0",
|
||||
"@octokit/plugin-throttling": "^9.4.0",
|
||||
"@octokit/rest": "^21.1.1",
|
||||
"discord.js": "^13.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
337
.github/workflows/scripts/releases/generate-release-notes/package-lock.json
generated
vendored
337
.github/workflows/scripts/releases/generate-release-notes/package-lock.json
generated
vendored
@@ -1,22 +1,33 @@
|
||||
{
|
||||
"name": "generate-release-notes",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": {
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
"@octokit/plugin-throttling": "^3.5.2",
|
||||
"@octokit/rest": "^21.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
|
||||
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
|
||||
"requires": {
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"@octokit/core": {
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz",
|
||||
"integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==",
|
||||
"requires": {
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.0",
|
||||
@@ -26,76 +37,60 @@
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/endpoint": {
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "6.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
|
||||
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
|
||||
"requires": {
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/graphql": {
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
|
||||
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
|
||||
"requires": {
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.1.0.tgz",
|
||||
"integrity": "sha512-dWZfYvCCdjZzDYA3lIAMF72Q0jld8xidqCq5Ryw09eBJXZdcM6he0vWBTvw/b5UnGYqexxOyHWgfrsTlUJL3Gw=="
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
"version": "2.16.9",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.9.tgz",
|
||||
"integrity": "sha512-gfSCMgz5scFKsR0dW4jaYsDJVt/UwCHp4dF7sHlmSekZvwzvLiOAGZ4MQkEsL5DW9hIk2W+UQkYZMTA1b6Wsqw==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.33.0"
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-request-log": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
|
||||
"integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA=="
|
||||
},
|
||||
"@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.12.1.tgz",
|
||||
"integrity": "sha512-0nY3htfl6x9UkPcqv8pm9vOC/bTA7f4IMDWln13neHRdNWQvOQgZ9fRxK7BAc74rye4yVINEFi9Yb9rnGUvosA==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.33.0",
|
||||
"deprecation": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-retry": {
|
||||
"node_modules/@octokit/plugin-retry": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-3.0.9.tgz",
|
||||
"integrity": "sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ==",
|
||||
"requires": {
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"bottleneck": "^2.15.3"
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-throttling": {
|
||||
"node_modules/@octokit/plugin-throttling": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-3.5.2.tgz",
|
||||
"integrity": "sha512-Eu7kfJxU8vmHqWGNszWpg+GVp2tnAfax3XQV5CkYPEE69C+KvInJXW9WajgSeW+cxYe0UVdouzCtcreGNuJo7A==",
|
||||
"requires": {
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.1",
|
||||
"bottleneck": "^2.15.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": "^3.5.0"
|
||||
}
|
||||
},
|
||||
"@octokit/request": {
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.2.tgz",
|
||||
"integrity": "sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA==",
|
||||
"requires": {
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
@@ -104,99 +99,295 @@
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/request-error": {
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
||||
"requires": {
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"@octokit/rest": {
|
||||
"version": "18.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz",
|
||||
"integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==",
|
||||
"requires": {
|
||||
"@octokit/core": "^3.5.1",
|
||||
"@octokit/plugin-paginate-rest": "^2.16.8",
|
||||
"@octokit/plugin-request-log": "^1.0.4",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^5.12.0"
|
||||
"node_modules/@octokit/rest": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-21.1.1.tgz",
|
||||
"integrity": "sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/core": "^6.1.4",
|
||||
"@octokit/plugin-paginate-rest": "^11.4.2",
|
||||
"@octokit/plugin-request-log": "^5.3.1",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^13.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/auth-token": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz",
|
||||
"integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/core": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.4.tgz",
|
||||
"integrity": "sha512-lAS9k7d6I0MPN+gb9bKDt7X8SdxknYqAMh44S5L+lNqIN2NuV8nvv3g8rPp7MuRxcOpxpUIATWprO0C34a8Qmg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^5.0.0",
|
||||
"@octokit/graphql": "^8.1.2",
|
||||
"@octokit/request": "^9.2.1",
|
||||
"@octokit/request-error": "^6.1.7",
|
||||
"@octokit/types": "^13.6.2",
|
||||
"before-after-hook": "^3.0.2",
|
||||
"universal-user-agent": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/endpoint": {
|
||||
"version": "10.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.3.tgz",
|
||||
"integrity": "sha512-nBRBMpKPhQUxCsQQeW+rCJ/OPSMcj3g0nfHn01zGYZXuNDvvXudF/TYY6APj5THlurerpFN4a/dQAIAaM6BYhA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.6.2",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/graphql": {
|
||||
"version": "8.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.1.tgz",
|
||||
"integrity": "sha512-n57hXtOoHrhwTWdvhVkdJHdhTv0JstjDbDRhJfwIRNfFqmSo1DaK/mD2syoNUoLCyqSjBpGAKOG0BuwF392slw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/request": "^9.2.2",
|
||||
"@octokit/types": "^13.8.0",
|
||||
"universal-user-agent": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/plugin-paginate-rest": {
|
||||
"version": "11.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.2.tgz",
|
||||
"integrity": "sha512-BXJ7XPCTDXFF+wxcg/zscfgw2O/iDPtNSkwwR1W1W5c4Mb3zav/M2XvxQ23nVmKj7jpweB4g8viMeCQdm7LMVA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/plugin-request-log": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-5.3.1.tgz",
|
||||
"integrity": "sha512-n/lNeCtq+9ofhC15xzmJCNKP2BWTv8Ih2TTy+jatNCCq/gQP/V7rK3fjIfuz0pDWDALO/o/4QY4hyOF6TQQFUw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "13.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.1.tgz",
|
||||
"integrity": "sha512-o8uOBdsyR+WR8MK9Cco8dCgvG13H1RlM1nWnK/W7TEACQBFux/vPREgKucxUfuDQ5yi1T3hGf4C5ZmZXAERgwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/request": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.2.tgz",
|
||||
"integrity": "sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^10.1.3",
|
||||
"@octokit/request-error": "^6.1.7",
|
||||
"@octokit/types": "^13.6.2",
|
||||
"fast-content-type-parse": "^2.0.0",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/request-error": {
|
||||
"version": "6.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.7.tgz",
|
||||
"integrity": "sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/before-after-hook": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz",
|
||||
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/universal-user-agent": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "6.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.33.0.tgz",
|
||||
"integrity": "sha512-0zffZ048M0UhthyPXQHLz4038Ak46nMWZXkzlXvXB/M/L1jYPBceq4iZj4qjKVrvveaJrrgKdJ9+3yUuITfcCw==",
|
||||
"requires": {
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^11.1.0"
|
||||
}
|
||||
},
|
||||
"before-after-hook": {
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
|
||||
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
|
||||
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==",
|
||||
"peer": true
|
||||
},
|
||||
"bottleneck": {
|
||||
"node_modules/bottleneck": {
|
||||
"version": "2.19.5",
|
||||
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
|
||||
"integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="
|
||||
},
|
||||
"deprecation": {
|
||||
"node_modules/deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
|
||||
"peer": true
|
||||
},
|
||||
"is-plain-object": {
|
||||
"node_modules/fast-content-type-parse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz",
|
||||
"integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"requires": {
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"requires": {
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"tr46": {
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
|
||||
"peer": true
|
||||
},
|
||||
"universal-user-agent": {
|
||||
"node_modules/universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==",
|
||||
"peer": true
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
|
||||
"peer": true
|
||||
},
|
||||
"whatwg-url": {
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"requires": {
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"peer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
"dependencies": {
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
"@octokit/plugin-throttling": "^3.5.2",
|
||||
"@octokit/rest": "^18.12.0"
|
||||
"@octokit/rest": "^21.1.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,16 +44,17 @@ cd "%BUILDDIR%"
|
||||
|
||||
set FREETYPE=2.13.3
|
||||
set HARFBUZZ=10.0.1
|
||||
set LIBJPEG=9f
|
||||
set LIBJPEGTURBO=3.1.0
|
||||
set LIBPNG=1645
|
||||
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
set QT=6.8.1
|
||||
set QT=6.8.2
|
||||
set QTMINOR=6.8
|
||||
set SDL=SDL2-2.30.11
|
||||
set SDL=SDL3-3.2.8
|
||||
set WEBP=1.5.0
|
||||
set ZLIB=1.3.1
|
||||
set ZLIBSHORT=131
|
||||
set ZSTD=1.5.6
|
||||
set ZSTD=1.5.7
|
||||
set KDDOCKWIDGETS=2.2.1
|
||||
|
||||
set SHADERC=2024.1
|
||||
set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -63,18 +64,18 @@ set SHADERC_SPIRVTOOLS=dd4b663e13c07fea4fbb3f70c1c91c86731099f7
|
||||
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
|
||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
|
||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1645.zip a66c4b1350b67776e90263e2550933067cd9ccbd318db489f84dcc0d2b033249 || goto error
|
||||
call :downloadfile "jpegsr%LIBJPEG%.zip" https://ijg.org/files/jpegsr%LIBJPEG%.zip 6255da8c89e09d694e6800688c76145eb6870a76ac0d36c74fccd61b3940aafa || goto error
|
||||
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 || goto error
|
||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" a0b3e7ac5f708042683ff0f22e069bdf75563540c615f9854ecc9bc8913e2488 || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 7f8ff5c8246db4145301bc122601a5f8cef25ee2c326eddb3e88668849c61ddf || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 102539447c1c76d206f24bcca2c911270cf53991548d9c3d7d0d01855f651e3b || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 33ccac9f99a357ffd83cb2d7179a0c0ffcba85a14d23d86619d5dc9721ded42f || goto error
|
||||
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
|
||||
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
|
||||
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
|
||||
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
|
||||
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v2.2.1.zip" 78b5e242bf47476e150175b7de934ab84069459e151beb2d5ce84fd067138aa5 || goto error
|
||||
|
||||
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 6c9f42ed6bf42750f5369b089909abfdcf0101488b4a1f41116d5159d00af8e7 || goto error
|
||||
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 03ad8a6fa987af4653d0cfe6bdaed41bcf617f1366a151fb1574da75950cd3e8 || goto error
|
||||
@@ -108,11 +109,10 @@ cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo Building libjpeg...
|
||||
rmdir /S /Q "jpeg-%LIBJPEG%"
|
||||
%SEVENZIP% x "jpegsr%LIBJPEG%.zip" || goto error
|
||||
cd "jpeg-%LIBJPEG%" || goto error
|
||||
%PATCH% -p1 < "%SCRIPTDIR%\libjpeg-cmake.patch" || goto error
|
||||
echo Building libjpegturbo...
|
||||
rmdir /S /Q "libjpeg-turbo-%LIBJPEGTURBO%"
|
||||
tar -xf "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" || goto error
|
||||
cd "libjpeg-turbo-%LIBJPEGTURBO%" || goto error
|
||||
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=OFF -B build -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
@@ -159,7 +159,6 @@ echo Building Zstandard...
|
||||
rmdir /S /Q "zstd-%ZSTD%"
|
||||
%SEVENZIP% x "-x^!zstd-%ZSTD%\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
|
||||
cd "zstd-%ZSTD%"
|
||||
%PATCH% -p1 < "..\zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" || goto error
|
||||
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
@@ -181,7 +180,7 @@ cd "%SDL%" || goto error
|
||||
cmake -B build %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
copy build\SDL2.pdb "%INSTALLDIR%\bin" || goto error
|
||||
copy build\SDL3.pdb "%INSTALLDIR%\bin" || goto error
|
||||
cd .. || goto error
|
||||
|
||||
if %DEBUG%==1 (
|
||||
@@ -243,6 +242,16 @@ cmake --build . --parallel || goto error
|
||||
ninja install || goto error
|
||||
cd ..\.. || goto error
|
||||
|
||||
echo "Building KDDockWidgets..."
|
||||
rmdir /S /Q "KDDockWidgets-%KDDOCKWIDGETS%"
|
||||
%SEVENZIP% x "KDDockWidgets-%KDDOCKWIDGETS%.zip" || goto error
|
||||
cd "KDDockWidgets-%KDDOCKWIDGETS%" || goto error
|
||||
%PATCH% -p1 < "%SCRIPTDIR%\..\common\kddockwidgets-dodgy-include.patch" || goto error
|
||||
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DKDDockWidgets_QT6=true -DKDDockWidgets_EXAMPLES=false -DKDDockWidgets_FRONTENDS=qtwidgets -B build -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo Building shaderc...
|
||||
rmdir /S /Q "shaderc-%SHADERC%"
|
||||
%SEVENZIP% x "shaderc-%SHADERC%.zip" || goto error
|
||||
|
||||
@@ -42,16 +42,17 @@ cd "%BUILDDIR%"
|
||||
|
||||
set FREETYPE=2.13.3
|
||||
set HARFBUZZ=10.0.1
|
||||
set LIBJPEG=9f
|
||||
set LIBJPEGTURBO=3.1.0
|
||||
set LIBPNG=1645
|
||||
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
set QT=6.8.1
|
||||
set QT=6.8.2
|
||||
set QTMINOR=6.8
|
||||
set SDL=SDL2-2.30.11
|
||||
set SDL=SDL3-3.2.8
|
||||
set WEBP=1.5.0
|
||||
set ZLIB=1.3.1
|
||||
set ZLIBSHORT=131
|
||||
set ZSTD=1.5.6
|
||||
set ZSTD=1.5.7
|
||||
set KDDOCKWIDGETS=2.2.1
|
||||
|
||||
set SHADERC=2024.1
|
||||
set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -61,18 +62,18 @@ set SHADERC_SPIRVTOOLS=dd4b663e13c07fea4fbb3f70c1c91c86731099f7
|
||||
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
|
||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
|
||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1645.zip a66c4b1350b67776e90263e2550933067cd9ccbd318db489f84dcc0d2b033249 || goto error
|
||||
call :downloadfile "jpegsr%LIBJPEG%.zip" https://ijg.org/files/jpegsr%LIBJPEG%.zip 6255da8c89e09d694e6800688c76145eb6870a76ac0d36c74fccd61b3940aafa || goto error
|
||||
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 || goto error
|
||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" a0b3e7ac5f708042683ff0f22e069bdf75563540c615f9854ecc9bc8913e2488 || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 7f8ff5c8246db4145301bc122601a5f8cef25ee2c326eddb3e88668849c61ddf || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 102539447c1c76d206f24bcca2c911270cf53991548d9c3d7d0d01855f651e3b || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 33ccac9f99a357ffd83cb2d7179a0c0ffcba85a14d23d86619d5dc9721ded42f || goto error
|
||||
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
|
||||
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
|
||||
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
|
||||
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
|
||||
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v2.2.1.zip" 78b5e242bf47476e150175b7de934ab84069459e151beb2d5ce84fd067138aa5 || goto error
|
||||
|
||||
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 6c9f42ed6bf42750f5369b089909abfdcf0101488b4a1f41116d5159d00af8e7 || goto error
|
||||
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 03ad8a6fa987af4653d0cfe6bdaed41bcf617f1366a151fb1574da75950cd3e8 || goto error
|
||||
@@ -105,11 +106,10 @@ cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo Building libjpeg...
|
||||
rmdir /S /Q "jpeg-%LIBJPEG%"
|
||||
%SEVENZIP% x "jpegsr%LIBJPEG%.zip" || goto error
|
||||
cd "jpeg-%LIBJPEG%" || goto error
|
||||
%PATCH% -p1 < "%SCRIPTDIR%\libjpeg-cmake.patch" || goto error
|
||||
echo Building libjpegturbo...
|
||||
rmdir /S /Q "libjpeg-turbo-%LIBJPEGTURBO%"
|
||||
tar -xf "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" || goto error
|
||||
cd "libjpeg-turbo-%LIBJPEGTURBO%" || goto error
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=OFF -B build -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
@@ -156,7 +156,6 @@ echo Building Zstandard...
|
||||
rmdir /S /Q "zstd-%ZSTD%"
|
||||
%SEVENZIP% x "-x^!zstd-%ZSTD%\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
|
||||
cd "zstd-%ZSTD%"
|
||||
%PATCH% -p1 < "..\zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" || goto error
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
@@ -178,7 +177,7 @@ cd "%SDL%" || goto error
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
copy build\SDL2.pdb "%INSTALLDIR%\bin" || goto error
|
||||
copy build\SDL3.pdb "%INSTALLDIR%\bin" || goto error
|
||||
cd .. || goto error
|
||||
|
||||
if %DEBUG%==1 (
|
||||
@@ -247,6 +246,16 @@ cmake --build . --parallel || goto error
|
||||
ninja install || goto error
|
||||
cd ..\.. || goto error
|
||||
|
||||
echo "Building KDDockWidgets..."
|
||||
rmdir /S /Q "KDDockWidgets-%KDDOCKWIDGETS%"
|
||||
%SEVENZIP% x "KDDockWidgets-%KDDOCKWIDGETS%.zip" || goto error
|
||||
cd "KDDockWidgets-%KDDOCKWIDGETS%" || goto error
|
||||
%PATCH% -p1 < "%SCRIPTDIR%\..\common\kddockwidgets-dodgy-include.patch" || goto error
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DKDDockWidgets_QT6=true -DKDDockWidgets_EXAMPLES=false -DKDDockWidgets_FRONTENDS=qtwidgets -B build -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo Building shaderc...
|
||||
rmdir /S /Q "shaderc-%SHADERC%"
|
||||
%SEVENZIP% x "shaderc-%SHADERC%.zip" || goto error
|
||||
|
||||
@@ -1,422 +0,0 @@
|
||||
diff -ruN jpeg-9f/CMakeLists.txt jpeg-9f-new/CMakeLists.txt
|
||||
--- jpeg-9f/CMakeLists.txt 1970-01-01 10:00:00.000000000 +1000
|
||||
+++ jpeg-9f-new/CMakeLists.txt 2024-03-23 21:29:37.969221600 +1000
|
||||
@@ -0,0 +1,110 @@
|
||||
+# CMake configuration for IJG libjpeg
|
||||
+# Modified from https://github.com/csparker247/jpeg-cmake/blob/develop/resources/CMakeLists.txt
|
||||
+# To install, copy this file and jconfig.h.in into a libjpeg source directory
|
||||
+# Adapted from LuaDist's CMakeLists
|
||||
+# https://github.com/LuaDist/libjpeg/blob/master/CMakeLists.txt
|
||||
+
|
||||
+cmake_minimum_required(VERSION 3.5)
|
||||
+
|
||||
+### Setup the project ###
|
||||
+file(READ "configure.ac" ac)
|
||||
+string(REGEX MATCH "AC_INIT\\(\\[libjpeg\\],\ \\[([0-9]*\\.[0-9]*\\.[0-9]*)\\]\\)" _ ${ac})
|
||||
+set(version ${CMAKE_MATCH_1})
|
||||
+project(libjpeg VERSION ${version} LANGUAGES C)
|
||||
+set(C_STANDARD 99)
|
||||
+
|
||||
+### Include extra packages ###
|
||||
+include(CMakeDependentOption)
|
||||
+include(GNUInstallDirs)
|
||||
+
|
||||
+### Options ###
|
||||
+option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||
+option(BUILD_STATIC_LIBS "Build static libraries" ON)
|
||||
+
|
||||
+# Make sure we build at least one library
|
||||
+if(NOT(BUILD_SHARED_LIBS OR BUILD_STATIC_LIBS))
|
||||
+ message(FATAL_ERROR "Both static and shared libraries are disabled. Nothing will be built.")
|
||||
+endif()
|
||||
+
|
||||
+### Configure jconfig.h ###
|
||||
+include(ConfigureJConfig.cmake)
|
||||
+
|
||||
+### Build the object library ###
|
||||
+set(PUBLIC_HDRS
|
||||
+ jconfig.h
|
||||
+ jerror.h
|
||||
+ jmorecfg.h
|
||||
+ jpeglib.h
|
||||
+)
|
||||
+
|
||||
+set(SRCS
|
||||
+ jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c
|
||||
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c
|
||||
+ jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c jdarith.c
|
||||
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c jdinput.c
|
||||
+ jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdpostct.c jdsample.c jdtrans.c
|
||||
+ jerror.c jfdctflt.c jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c
|
||||
+ jmemmgr.c jmemnobs.c jquant1.c jquant2.c jutils.c
|
||||
+)
|
||||
+
|
||||
+### Create static and shared libs ###
|
||||
+if(BUILD_SHARED_LIBS)
|
||||
+ add_library(libjpeg SHARED ${SRCS})
|
||||
+ target_compile_definitions(libjpeg PRIVATE COMPILING_LIBJPEG)
|
||||
+ target_include_directories(libjpeg
|
||||
+ PUBLIC
|
||||
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
+ $<INSTALL_INTERFACE:include>
|
||||
+ )
|
||||
+ set_target_properties(libjpeg
|
||||
+ PROPERTIES
|
||||
+ VERSION ${PROJECT_VERSION_MAJOR}
|
||||
+ POSITION_INDEPENDENT_CODE ON
|
||||
+ CLEAN_DIRECT_OUTPUT ON
|
||||
+ PUBLIC_HEADER "${PUBLIC_HDRS}"
|
||||
+ )
|
||||
+ install(TARGETS libjpeg
|
||||
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
+ )
|
||||
+endif()
|
||||
+
|
||||
+if(BUILD_STATIC_LIBS)
|
||||
+ add_library(libjpeg_static STATIC $<TARGET_OBJECTS:jpeg_objs>)
|
||||
+ target_include_directories(libjpeg_static
|
||||
+ PUBLIC
|
||||
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
+ $<INSTALL_INTERFACE:include>
|
||||
+ )
|
||||
+ set_target_properties(libjpeg_static
|
||||
+ PROPERTIES
|
||||
+ OUTPUT_NAME jpeg
|
||||
+ VERSION ${PROJECT_VERSION_MAJOR}
|
||||
+ POSITION_INDEPENDENT_CODE ON
|
||||
+ CLEAN_DIRECT_OUTPUT ON
|
||||
+ PUBLIC_HEADER "${PUBLIC_HDRS}"
|
||||
+ )
|
||||
+ install(TARGETS libjpeg_static
|
||||
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
+ )
|
||||
+endif()
|
||||
+
|
||||
+# Configure and install pkg-config and libtool files
|
||||
+if(BUILD_STATIC_LIBS OR BUILD_SHARED_LIBS)
|
||||
+ # Compute the la file's weird version number
|
||||
+ math(EXPR JPEG_CONF_VER_MAJOR "${PROJECT_VERSION_MAJOR} + ${PROJECT_VERSION_MINOR}")
|
||||
+ set(JPEG_LIB_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||
+ set(JPEG_LIB_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
||||
+
|
||||
+ # Configure and install
|
||||
+ configure_file(libjpeg.pc.cmakein libjpeg.pc @ONLY)
|
||||
+ install(FILES
|
||||
+ ${CMAKE_CURRENT_BINARY_DIR}/libjpeg.pc
|
||||
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig
|
||||
+ )
|
||||
+endif()
|
||||
+
|
||||
diff -ruN jpeg-9f/ConfigureJConfig.cmake jpeg-9f-new/ConfigureJConfig.cmake
|
||||
--- jpeg-9f/ConfigureJConfig.cmake 1970-01-01 10:00:00.000000000 +1000
|
||||
+++ jpeg-9f-new/ConfigureJConfig.cmake 2024-03-23 21:09:37.223882900 +1000
|
||||
@@ -0,0 +1,95 @@
|
||||
+include(CheckIncludeFile)
|
||||
+include(CheckSymbolExists)
|
||||
+include(CheckTypeSize)
|
||||
+
|
||||
+# Define this if your system has an ANSI-conforming <stddef.h> file.
|
||||
+check_include_file(stddef.h HAVE_STDDEF_H)
|
||||
+
|
||||
+# Define this if your system has an ANSI-conforming <stdlib.h> file.
|
||||
+check_include_file(stdlib.h HAVE_STDLIB_H)
|
||||
+
|
||||
+# Does your compiler support function prototypes?
|
||||
+# (If not, you also need to use ansi2knr, see install.txt)
|
||||
+set(HAVE_PROTOTYPES true CACHE BOOL "Does your compiler support function prototypes?")
|
||||
+
|
||||
+# Does your compiler support the declaration "unsigned char" ?
|
||||
+# How about "unsigned short" ?
|
||||
+check_type_size("unsigned char" UNSIGNED_CHAR LANGUAGE C)
|
||||
+check_type_size("unsigned short" UNSIGNED_SHORT LANGUAGE C)
|
||||
+
|
||||
+# Define "void" as "char" if your compiler doesn't know about type void.
|
||||
+# NOTE: be sure to define void such that "void *" represents the most general
|
||||
+# pointer type, e.g., that returned by malloc().
|
||||
+# NOT IMPLEMENTED: Modify in jconfig.h.in #
|
||||
+
|
||||
+# Define "const" as empty if your compiler doesn't know the "const" keyword.
|
||||
+# NOT IMPLEMENTED: Modify in jconfig.h.in #
|
||||
+
|
||||
+# Define this if an ordinary "char" type is unsigned.
|
||||
+# If you're not sure, leaving it undefined will work at some cost in speed.
|
||||
+# If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal.
|
||||
+set(CHAR_IS_UNSIGNED false CACHE BOOL "char type is unsigned")
|
||||
+
|
||||
+# Define this if your system does not have an ANSI/SysV <string.h>,
|
||||
+# but does have a BSD-style <strings.h>.
|
||||
+set(NEED_BSD_STRINGS false CACHE BOOL "Use BSD <strings.h>. Use only if system lacks ANSI/SysV <strings.h>")
|
||||
+
|
||||
+# Define this if your system does not provide typedef size_t in any of the
|
||||
+# ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in
|
||||
+# <sys/types.h> instead.
|
||||
+set(NEED_SYS_TYPES_H false CACHE BOOL "size_t defined in <sys/types.h>")
|
||||
+
|
||||
+# For 80x86 machines, you need to define NEED_FAR_POINTERS,
|
||||
+# unless you are using a large-data memory model or 80386 flat-memory mode.
|
||||
+# On less brain-damaged CPUs this symbol must not be defined.
|
||||
+# (Defining this symbol causes large data structures to be referenced through
|
||||
+# "far" pointers and to be allocated with a special version of malloc.)
|
||||
+set(NEED_FAR_POINTERS false CACHE BOOL "Reference large data structures through 'far' pointers allocated with a special version of malloc")
|
||||
+
|
||||
+# Define this if your linker needs global names to be unique in less
|
||||
+# than the first 15 characters.
|
||||
+set(NEED_SHORT_EXTERNAL_NAMES false CACHE BOOL "Global names must be unique in less than the first 15 characters")
|
||||
+
|
||||
+# Although a real ANSI C compiler can deal perfectly well with pointers to
|
||||
+# unspecified structures (see "incomplete types" in the spec), a few pre-ANSI
|
||||
+# and pseudo-ANSI compilers get confused. To keep one of these bozos happy,
|
||||
+# define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you
|
||||
+# actually get "missing structure definition" warnings or errors while
|
||||
+# compiling the JPEG code.
|
||||
+set(INCOMPLETE_TYPES_BROKEN false CACHE BOOL "Disable pointers to unspecified structures")
|
||||
+
|
||||
+# Define "boolean" as unsigned char, not enum, on Windows systems.
|
||||
+# NOT IMPLEMENTED: Modify in jconfig.h.in #
|
||||
+
|
||||
+# The following options affect code selection within the JPEG library,
|
||||
+# but they don't need to be visible to applications using the library.
|
||||
+# To minimize application namespace pollution, the symbols won't be
|
||||
+# defined unless JPEG_INTERNALS has been defined.
|
||||
+#
|
||||
+
|
||||
+# Define this if your compiler implements ">>" on signed values as a logical
|
||||
+# (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift,
|
||||
+# which is the normal and rational definition.
|
||||
+set(RIGHT_SHIFT_IS_UNSIGNED false CACHE BOOL "Compiler implements >> on signed values as a logical (unsigned) shift")
|
||||
+
|
||||
+# The remaining options do not affect the JPEG library proper,
|
||||
+# but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c).
|
||||
+# Other applications can ignore these.
|
||||
+#
|
||||
+
|
||||
+mark_as_advanced(FORCE
|
||||
+ HAVE_PROTOTYPES
|
||||
+ HAVE_UNSIGNED_CHAR
|
||||
+ HAVE_UNSIGNED_SHORT
|
||||
+ CHAR_IS_UNSIGNED
|
||||
+ HAVE_STDDEF_H
|
||||
+ HAVE_STDLIB_H
|
||||
+ NEED_BSD_STRINGS
|
||||
+ NEED_SYS_TYPES_H
|
||||
+ NEED_FAR_POINTERS
|
||||
+ NEED_SHORT_EXTERNAL_NAMES
|
||||
+ INCOMPLETE_TYPES_BROKEN
|
||||
+ RIGHT_SHIFT_IS_UNSIGNED
|
||||
+)
|
||||
+
|
||||
+configure_file(jconfig.h.in ${CMAKE_CURRENT_SOURCE_DIR}/jconfig.h)
|
||||
diff -ruN jpeg-9f/jconfig.h.in jpeg-9f-new/jconfig.h.in
|
||||
--- jpeg-9f/jconfig.h.in 1970-01-01 10:00:00.000000000 +1000
|
||||
+++ jpeg-9f-new/jconfig.h.in 2024-03-23 21:06:05.204994600 +1000
|
||||
@@ -0,0 +1,173 @@
|
||||
+/*
|
||||
+ * jconfig.h.in
|
||||
+ *
|
||||
+ * Copyright (C) 1991-1994, Thomas G. Lane.
|
||||
+ * Modified 2009-2013 by Guido Vollbeding.
|
||||
+ * This file is part of the Independent JPEG Group's software.
|
||||
+ * For conditions of distribution and use, see the accompanying README file.
|
||||
+ *
|
||||
+ * This file is a modification of jconfig.txt from libjpeg. In addition to
|
||||
+ * documenting the configuration options that are required to customize the
|
||||
+ * JPEG software for a particular system, it is used by jpeg-cmake to configure
|
||||
+ * jconfig.h
|
||||
+ */
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * These symbols indicate the properties of your machine or compiler.
|
||||
+ * #define the symbol if yes, #undef it if no.
|
||||
+ */
|
||||
+
|
||||
+/* Does your compiler support function prototypes?
|
||||
+ * (If not, you also need to use ansi2knr, see install.txt)
|
||||
+ */
|
||||
+#cmakedefine HAVE_PROTOTYPES
|
||||
+
|
||||
+/* Does your compiler support the declaration "unsigned char" ?
|
||||
+ * How about "unsigned short" ?
|
||||
+ */
|
||||
+#cmakedefine HAVE_UNSIGNED_CHAR
|
||||
+#cmakedefine HAVE_UNSIGNED_SHORT
|
||||
+
|
||||
+/* Define "void" as "char" if your compiler doesn't know about type void.
|
||||
+ * NOTE: be sure to define void such that "void *" represents the most general
|
||||
+ * pointer type, e.g., that returned by malloc().
|
||||
+ */
|
||||
+/* #define void char */
|
||||
+
|
||||
+/* Define "const" as empty if your compiler doesn't know the "const" keyword.
|
||||
+ */
|
||||
+/* #define const */
|
||||
+
|
||||
+/* Define this if an ordinary "char" type is unsigned.
|
||||
+ * If you're not sure, leaving it undefined will work at some cost in speed.
|
||||
+ * If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal.
|
||||
+ */
|
||||
+#cmakedefine CHAR_IS_UNSIGNED
|
||||
+
|
||||
+/* Define this if your system has an ANSI-conforming <stddef.h> file.
|
||||
+ */
|
||||
+#cmakedefine HAVE_STDDEF_H
|
||||
+
|
||||
+/* Define this if your system has an ANSI-conforming <stdlib.h> file.
|
||||
+ */
|
||||
+#cmakedefine HAVE_STDLIB_H
|
||||
+
|
||||
+/* Define this if your system does not have an ANSI/SysV <string.h>,
|
||||
+ * but does have a BSD-style <strings.h>.
|
||||
+ */
|
||||
+#cmakedefine NEED_BSD_STRINGS
|
||||
+
|
||||
+/* Define this if your system does not provide typedef size_t in any of the
|
||||
+ * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in
|
||||
+ * <sys/types.h> instead.
|
||||
+ */
|
||||
+#cmakedefine NEED_SYS_TYPES_H
|
||||
+
|
||||
+/* For 80x86 machines, you need to define NEED_FAR_POINTERS,
|
||||
+ * unless you are using a large-data memory model or 80386 flat-memory mode.
|
||||
+ * On less brain-damaged CPUs this symbol must not be defined.
|
||||
+ * (Defining this symbol causes large data structures to be referenced through
|
||||
+ * "far" pointers and to be allocated with a special version of malloc.)
|
||||
+ */
|
||||
+#cmakedefine NEED_FAR_POINTERS
|
||||
+
|
||||
+/* Define this if your linker needs global names to be unique in less
|
||||
+ * than the first 15 characters.
|
||||
+ */
|
||||
+#cmakedefine NEED_SHORT_EXTERNAL_NAMES
|
||||
+
|
||||
+/* Although a real ANSI C compiler can deal perfectly well with pointers to
|
||||
+ * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI
|
||||
+ * and pseudo-ANSI compilers get confused. To keep one of these bozos happy,
|
||||
+ * define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you
|
||||
+ * actually get "missing structure definition" warnings or errors while
|
||||
+ * compiling the JPEG code.
|
||||
+ */
|
||||
+#cmakedefine INCOMPLETE_TYPES_BROKEN
|
||||
+
|
||||
+/* Define "boolean" as unsigned char, not enum, on Windows systems.
|
||||
+ */
|
||||
+#ifdef _WIN32
|
||||
+#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
|
||||
+typedef unsigned char boolean;
|
||||
+#endif
|
||||
+#ifndef FALSE /* in case these macros already exist */
|
||||
+#define FALSE 0 /* values of boolean */
|
||||
+#endif
|
||||
+#ifndef TRUE
|
||||
+#define TRUE 1
|
||||
+#endif
|
||||
+#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * The following options affect code selection within the JPEG library,
|
||||
+ * but they don't need to be visible to applications using the library.
|
||||
+ * To minimize application namespace pollution, the symbols won't be
|
||||
+ * defined unless JPEG_INTERNALS has been defined.
|
||||
+ */
|
||||
+
|
||||
+#ifdef JPEG_INTERNALS
|
||||
+
|
||||
+/* Define this if your compiler implements ">>" on signed values as a logical
|
||||
+ * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift,
|
||||
+ * which is the normal and rational definition.
|
||||
+ */
|
||||
+#cmakedefine RIGHT_SHIFT_IS_UNSIGNED
|
||||
+
|
||||
+
|
||||
+#endif /* JPEG_INTERNALS */
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * The remaining options do not affect the JPEG library proper,
|
||||
+ * but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c).
|
||||
+ * Other applications can ignore these.
|
||||
+ */
|
||||
+
|
||||
+#ifdef JPEG_CJPEG_DJPEG
|
||||
+
|
||||
+/* These defines indicate which image (non-JPEG) file formats are allowed. */
|
||||
+
|
||||
+#cmakedefine BMP_SUPPORTED /* BMP image file format */
|
||||
+#cmakedefine GIF_SUPPORTED /* GIF image file format */
|
||||
+#cmakedefine PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
|
||||
+#cmakedefine RLE_SUPPORTED /* Utah RLE image file format */
|
||||
+#cmakedefine TARGA_SUPPORTED /* Targa image file format */
|
||||
+
|
||||
+/*
|
||||
+ * This defines the default output format for djpeg. Must be one of the FMT_*
|
||||
+ * enums found in djpeg.c or djpegalt.c
|
||||
+ */
|
||||
+#cmakedefine DEFAULT_FMT @DEFAULT_FMT@
|
||||
+
|
||||
+/* Define this if you want to name both input and output files on the command
|
||||
+ * line, rather than using stdout and optionally stdin. You MUST do this if
|
||||
+ * your system can't cope with binary I/O to stdin/stdout. See comments at
|
||||
+ * head of cjpeg.c or djpeg.c.
|
||||
+ */
|
||||
+#cmakedefine TWO_FILE_COMMANDLINE
|
||||
+
|
||||
+/* Define this if your system needs explicit cleanup of temporary files.
|
||||
+ * This is crucial under MS-DOS, where the temporary "files" may be areas
|
||||
+ * of extended memory; on most other systems it's not as important.
|
||||
+ */
|
||||
+#cmakedefine NEED_SIGNAL_CATCHER
|
||||
+
|
||||
+/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb").
|
||||
+ * This is necessary on systems that distinguish text files from binary files,
|
||||
+ * and is harmless on most systems that don't. If you have one of the rare
|
||||
+ * systems that complains about the "b" spec, define this symbol.
|
||||
+ */
|
||||
+#cmakedefine DONT_USE_B_MODE
|
||||
+
|
||||
+/* Define this if you want percent-done progress reports from cjpeg/djpeg.
|
||||
+ */
|
||||
+#cmakedefine PROGRESS_REPORT
|
||||
+
|
||||
+/* Define this if you *don't* want overwrite confirmation */
|
||||
+#cmakedefine NO_OVERWRITE_CHECK
|
||||
+
|
||||
+#endif /* JPEG_CJPEG_DJPEG */
|
||||
diff -ruN jpeg-9f/jmorecfg.h jpeg-9f-new/jmorecfg.h
|
||||
--- jpeg-9f/jmorecfg.h 2022-03-31 19:41:26.000000000 +1000
|
||||
+++ jpeg-9f-new/jmorecfg.h 2024-03-23 21:20:25.514814400 +1000
|
||||
@@ -244,8 +244,13 @@
|
||||
#define LOCAL(type) static type
|
||||
/* a function referenced thru EXTERNs: */
|
||||
#define GLOBAL(type) type
|
||||
+
|
||||
/* a reference to a GLOBAL function: */
|
||||
-#define EXTERN(type) extern type
|
||||
+#ifdef COMPILING_LIBJPEG
|
||||
+#define EXTERN(type) __declspec(dllexport) extern type
|
||||
+#else
|
||||
+#define EXTERN(type) __declspec(dllimport) extern type
|
||||
+#endif
|
||||
|
||||
|
||||
/* This macro is used to declare a "method", that is, a function pointer.
|
||||
diff -ruN jpeg-9f/libjpeg.pc.cmakein jpeg-9f-new/libjpeg.pc.cmakein
|
||||
--- jpeg-9f/libjpeg.pc.cmakein 1970-01-01 10:00:00.000000000 +1000
|
||||
+++ jpeg-9f-new/libjpeg.pc.cmakein 2024-03-23 21:06:13.922695100 +1000
|
||||
@@ -0,0 +1,10 @@
|
||||
+prefix=@CMAKE_INSTALL_PREFIX@
|
||||
+exec_prefix=${prefix}
|
||||
+libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||
+includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||
+
|
||||
+Name: libjpeg
|
||||
+Description: Reads and writes JPEG files
|
||||
+Version: @JPEG_LIB_VERSION_MAJOR@.@JPEG_LIB_VERSION_MINOR@.0
|
||||
+Libs: -L${libdir} -ljpeg
|
||||
+Cflags: -I${includedir}
|
||||
2
.github/workflows/triage_pr.yml
vendored
2
.github/workflows/triage_pr.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: xTVaser/first-interaction@v1.2.4
|
||||
- uses: xTVaser/first-interaction@d62d6eb3c1215eae9f9d6dbfabf12d6725834cb3
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
debug-mode: false
|
||||
|
||||
21
.github/workflows/windows_build_qt.yml
vendored
21
.github/workflows/windows_build_qt.yml
vendored
@@ -167,8 +167,27 @@ jobs:
|
||||
!./bin/**/*.pdb
|
||||
!./bin/**/*.lib
|
||||
|
||||
- name: Install the Breakpad Symbol Generator
|
||||
uses: baptiste0928/cargo-install@91c5da15570085bcde6f4d7aed98cb82d6769fd3
|
||||
with:
|
||||
crate: dump_syms
|
||||
|
||||
- name: Generate Breakpad Symbols # Also flatten pdbs to a 'symbols' directory for upload-artifact
|
||||
shell: pwsh
|
||||
run: |
|
||||
mkdir -Force symbols
|
||||
Get-ChildItem -Path ./bin -Recurse -File | Where-Object {
|
||||
($_.Extension -eq ".exe" -or $_.Extension -eq ".pdb") -and ($_.Name -notmatch "updater")
|
||||
} | ForEach-Object {
|
||||
& dump_syms $_.FullName >> symbols/pcsx2-qt.bpsym
|
||||
}
|
||||
Get-ChildItem -Path ./bin -Recurse -Filter "*.pdb" | ForEach-Object {
|
||||
Copy-Item $_.FullName -Destination symbols/
|
||||
}
|
||||
|
||||
- name: Upload artifact - with symbols
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}-symbols
|
||||
path: ./bin/**/*.pdb
|
||||
path: |
|
||||
./symbols
|
||||
|
||||
31
3rdparty/cpuinfo/src/arm/mach/init.c
vendored
31
3rdparty/cpuinfo/src/arm/mach/init.c
vendored
@@ -101,17 +101,35 @@ static enum cpuinfo_uarch decode_uarch(uint32_t cpu_family, uint32_t core_index,
|
||||
return cpuinfo_uarch_unknown;
|
||||
}
|
||||
|
||||
static void decode_package_name(char* package_name) {
|
||||
/* Small bodge until cpuinfo merges PR #246 */
|
||||
static int read_package_name_from_brand_string(char* package_name) {
|
||||
size_t size;
|
||||
if (sysctlbyname("machdep.cpu.brand_string", NULL, &size, NULL, 0) != 0) {
|
||||
sysctlfail:
|
||||
cpuinfo_log_warning("sysctlbyname(\"machdep.cpu.brand_string\") failed: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
char* brand_string = alloca(size);
|
||||
if (sysctlbyname("machdep.cpu.brand_string", brand_string, &size, NULL, 0) != 0)
|
||||
goto sysctlfail;
|
||||
cpuinfo_log_debug("machdep.cpu.brand_string: %s", brand_string);
|
||||
|
||||
strlcpy(package_name, brand_string, CPUINFO_PACKAGE_NAME_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int decode_package_name_from_hw_machine(char* package_name) {
|
||||
size_t size;
|
||||
if (sysctlbyname("hw.machine", NULL, &size, NULL, 0) != 0) {
|
||||
cpuinfo_log_warning("sysctlbyname(\"hw.machine\") failed: %s", strerror(errno));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
char* machine_name = alloca(size);
|
||||
if (sysctlbyname("hw.machine", machine_name, &size, NULL, 0) != 0) {
|
||||
cpuinfo_log_warning("sysctlbyname(\"hw.machine\") failed: %s", strerror(errno));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
cpuinfo_log_debug("hw.machine: %s", machine_name);
|
||||
|
||||
@@ -119,7 +137,7 @@ static void decode_package_name(char* package_name) {
|
||||
uint32_t major = 0, minor = 0;
|
||||
if (sscanf(machine_name, "%9[^,0123456789]%" SCNu32 ",%" SCNu32, name, &major, &minor) != 3) {
|
||||
cpuinfo_log_warning("parsing \"hw.machine\" failed: %s", strerror(errno));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t chip_model = 0;
|
||||
@@ -224,7 +242,9 @@ static void decode_package_name(char* package_name) {
|
||||
}
|
||||
if (chip_model != 0) {
|
||||
snprintf(package_name, CPUINFO_PACKAGE_NAME_MAX, "Apple A%" PRIu32 "%c", chip_model, suffix);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cpuinfo_arm_mach_init(void) {
|
||||
@@ -275,7 +295,8 @@ void cpuinfo_arm_mach_init(void) {
|
||||
.core_start = i * cores_per_package,
|
||||
.core_count = cores_per_package,
|
||||
};
|
||||
decode_package_name(packages[i].name);
|
||||
if (!read_package_name_from_brand_string(packages[i].name))
|
||||
decode_package_name_from_hw_machine(packages[i].name);
|
||||
}
|
||||
|
||||
const uint32_t cpu_family = get_sys_info_by_name("hw.cpufamily");
|
||||
|
||||
84
3rdparty/imgui/include/imgui.h
vendored
84
3rdparty/imgui/include/imgui.h
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.7
|
||||
// dear imgui, v1.91.8
|
||||
// (headers)
|
||||
|
||||
// Help:
|
||||
@@ -28,8 +28,8 @@
|
||||
|
||||
// Library Version
|
||||
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
|
||||
#define IMGUI_VERSION "1.91.7"
|
||||
#define IMGUI_VERSION_NUM 19170
|
||||
#define IMGUI_VERSION "1.91.8"
|
||||
#define IMGUI_VERSION_NUM 19180
|
||||
#define IMGUI_HAS_TABLE
|
||||
|
||||
/*
|
||||
@@ -158,7 +158,7 @@ typedef unsigned int ImU32; // 32-bit unsigned integer (often used to st
|
||||
typedef signed long long ImS64; // 64-bit signed integer
|
||||
typedef unsigned long long ImU64; // 64-bit unsigned integer
|
||||
|
||||
// Forward declarations
|
||||
// Forward declarations: ImDrawList, ImFontAtlas layer
|
||||
struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit()
|
||||
struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback)
|
||||
struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix.
|
||||
@@ -173,6 +173,8 @@ struct ImFontConfig; // Configuration data when adding a font or
|
||||
struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset)
|
||||
struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data
|
||||
struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using)
|
||||
|
||||
// Forward declarations: ImGui layer
|
||||
struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h)
|
||||
struct ImGuiIO; // Main configuration and I/O between your application and ImGui (also see: ImGuiPlatformIO)
|
||||
struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use)
|
||||
@@ -1009,6 +1011,7 @@ namespace ImGui
|
||||
IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); // did mouse button clicked? (went from !Down to Down). Same as GetMouseClickedCount() == 1.
|
||||
IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); // did mouse button released? (went from Down to !Down)
|
||||
IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); // did mouse button double-clicked? Same as GetMouseClickedCount() == 2. (note that a double-click will also report IsMouseClicked() == true)
|
||||
IMGUI_API bool IsMouseReleasedWithDelay(ImGuiMouseButton button, float delay); // delayed mouse release (use very sparingly!). Generally used with 'delay >= io.MouseDoubleClickTime' + combined with a 'io.MouseClickedLastCount==1' test. This is a very rarely used UI idiom, but some apps use this: e.g. MS Explorer single click on an icon to rename.
|
||||
IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button); // return the number of successive mouse-clicks at the time where a click happen (otherwise 0).
|
||||
IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block.
|
||||
IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available
|
||||
@@ -1751,10 +1754,16 @@ enum ImGuiColorEditFlags_
|
||||
ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source.
|
||||
ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default)
|
||||
|
||||
// Alpha preview
|
||||
// - Prior to 1.91.8 (2025/01/21): alpha was made opaque in the preview by default using old name ImGuiColorEditFlags_AlphaPreview.
|
||||
// - We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior.
|
||||
// - The new flags may be combined better and allow finer controls.
|
||||
ImGuiColorEditFlags_AlphaOpaque = 1 << 11, // // ColorEdit, ColorPicker, ColorButton: disable alpha in the preview,. Contrary to _NoAlpha it may still be edited when calling ColorEdit4()/ColorPicker4(). For ColorButton() this does the same as _NoAlpha.
|
||||
ImGuiColorEditFlags_AlphaNoBg = 1 << 12, // // ColorEdit, ColorPicker, ColorButton: disable rendering a checkerboard background behind transparent color.
|
||||
ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 13, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half transparent preview.
|
||||
|
||||
// User Options (right-click on widget to change some of them).
|
||||
ImGuiColorEditFlags_AlphaBar = 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker.
|
||||
ImGuiColorEditFlags_AlphaPreview = 1 << 17, // // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque.
|
||||
ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque.
|
||||
ImGuiColorEditFlags_HDR = 1 << 19, // // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well).
|
||||
ImGuiColorEditFlags_DisplayRGB = 1 << 20, // [Display] // ColorEdit: override _display_ type among RGB/HSV/Hex. ColorPicker: select any combination using one or more of RGB/HSV/Hex.
|
||||
ImGuiColorEditFlags_DisplayHSV = 1 << 21, // [Display] // "
|
||||
@@ -1771,12 +1780,16 @@ enum ImGuiColorEditFlags_
|
||||
ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar,
|
||||
|
||||
// [Internal] Masks
|
||||
ImGuiColorEditFlags_AlphaMask_ = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaOpaque | ImGuiColorEditFlags_AlphaNoBg | ImGuiColorEditFlags_AlphaPreviewHalf,
|
||||
ImGuiColorEditFlags_DisplayMask_ = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex,
|
||||
ImGuiColorEditFlags_DataTypeMask_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float,
|
||||
ImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar,
|
||||
ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV,
|
||||
|
||||
// Obsolete names
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
ImGuiColorEditFlags_AlphaPreview = 0, // [Removed in 1.91.8] This is the default now. Will display a checkerboard unless ImGuiColorEditFlags_AlphaNoBg is set.
|
||||
#endif
|
||||
//ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69]
|
||||
};
|
||||
|
||||
@@ -2403,6 +2416,7 @@ struct ImGuiIO
|
||||
ImU16 MouseClickedCount[5]; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down
|
||||
ImU16 MouseClickedLastCount[5]; // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done.
|
||||
bool MouseReleased[5]; // Mouse button went from Down to !Down
|
||||
double MouseReleasedTime[5]; // Time of last released (rarely used! but useful to handle delayed single-click when trying to disambiguate them from double-click).
|
||||
bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds.
|
||||
bool MouseDownOwnedUnlessPopupClose[5]; // Track if button was clicked inside a dear imgui window.
|
||||
bool MouseWheelRequestAxisSwap; // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system.
|
||||
@@ -2923,7 +2937,7 @@ struct ImGuiSelectionExternalStorage
|
||||
|
||||
// The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable baking.
|
||||
#ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX
|
||||
#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (63)
|
||||
#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (32)
|
||||
#endif
|
||||
|
||||
// ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h]
|
||||
@@ -2997,7 +3011,6 @@ struct ImDrawChannel
|
||||
ImVector<ImDrawIdx> _IdxBuffer;
|
||||
};
|
||||
|
||||
|
||||
// Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order.
|
||||
// This is used by the Columns/Tables API, so items of each column can be batched together in a same draw call.
|
||||
struct ImDrawListSplitter
|
||||
@@ -3232,26 +3245,27 @@ struct ImDrawData
|
||||
// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// A font input/source (we may rename this to ImFontSource in the future)
|
||||
struct ImFontConfig
|
||||
{
|
||||
void* FontData; // // TTF/OTF data
|
||||
int FontDataSize; // // TTF/OTF data size
|
||||
bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself).
|
||||
int FontNo; // 0 // Index of font within TTF/OTF file
|
||||
float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height).
|
||||
int OversampleH; // 2 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details.
|
||||
int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis.
|
||||
bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights.
|
||||
bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1.
|
||||
int FontNo; // 0 // Index of font within TTF/OTF file
|
||||
int OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details.
|
||||
int OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis.
|
||||
float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height).
|
||||
ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now.
|
||||
ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input.
|
||||
const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list).
|
||||
float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font
|
||||
float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs
|
||||
bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights.
|
||||
unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure.
|
||||
float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future.
|
||||
float RasterizerDensity; // 1.0f // DPI scale for rasterization, not altering other font metrics: make it easy to swap between e.g. a 100% and a 400% fonts for a zooming display. IMPORTANT: If you increase this it is expected that you increase font scale accordingly, otherwise quality may look lowered.
|
||||
ImWchar EllipsisChar; // 0 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used.
|
||||
ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used.
|
||||
|
||||
// [Internal]
|
||||
char Name[40]; // Name (strictly to ease debugging)
|
||||
@@ -3341,8 +3355,8 @@ struct ImFontAtlas
|
||||
IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_data_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp.
|
||||
IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter.
|
||||
IMGUI_API void ClearInputData(); // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts.
|
||||
IMGUI_API void ClearFonts(); // Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates).
|
||||
IMGUI_API void ClearTexData(); // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory.
|
||||
IMGUI_API void ClearFonts(); // Clear output font data (glyphs storage, UV coordinates).
|
||||
IMGUI_API void Clear(); // Clear all input and output.
|
||||
|
||||
// Build atlas, retrieve pixel data.
|
||||
@@ -3375,7 +3389,7 @@ struct ImFontAtlas
|
||||
IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters
|
||||
|
||||
//-------------------------------------------
|
||||
// [BETA] Custom Rectangles/Glyphs API
|
||||
// [ALPHA] Custom Rectangles/Glyphs API
|
||||
//-------------------------------------------
|
||||
|
||||
// You can request arbitrary rectangles to be packed into the atlas, for your own purposes.
|
||||
@@ -3401,11 +3415,11 @@ struct ImFontAtlas
|
||||
ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure.
|
||||
int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
|
||||
int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false).
|
||||
bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert.
|
||||
void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas).
|
||||
|
||||
// [Internal]
|
||||
// NB: Access texture data via GetTexData*() calls! Which will setup a default font for you.
|
||||
bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert.
|
||||
bool TexReady; // Set when texture was built matching current font input
|
||||
bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format.
|
||||
unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight
|
||||
@@ -3437,39 +3451,39 @@ struct ImFontAtlas
|
||||
struct ImFont
|
||||
{
|
||||
// [Internal] Members: Hot ~20/24 bytes (for CalcTextSize)
|
||||
ImVector<float> IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI).
|
||||
ImVector<float> IndexAdvanceX; // 12-16 // out // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI).
|
||||
float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX
|
||||
float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading)
|
||||
float FontSize; // 4 // in // Height of characters/line, set during loading (don't change after loading)
|
||||
|
||||
// [Internal] Members: Hot ~28/40 bytes (for RenderText loop)
|
||||
ImVector<ImWchar> IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point.
|
||||
ImVector<ImFontGlyph> Glyphs; // 12-16 // out // // All glyphs.
|
||||
ImVector<ImU16> IndexLookup; // 12-16 // out // Sparse. Index glyphs by Unicode code-point.
|
||||
ImVector<ImFontGlyph> Glyphs; // 12-16 // out // All glyphs.
|
||||
const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar)
|
||||
|
||||
// [Internal] Members: Cold ~32/40 bytes
|
||||
// Conceptually ConfigData[] is the list of font sources merged to create this font.
|
||||
ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into
|
||||
const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData to ConfigDataCount instances
|
||||
short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont.
|
||||
ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into
|
||||
const ImFontConfig* ConfigData; // 4-8 // in // Pointer within ContainerAtlas->ConfigData to ConfigDataCount instances
|
||||
short ConfigDataCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont.
|
||||
short EllipsisCharCount; // 1 // out // 1 or 3
|
||||
ImWchar EllipsisChar; // 2-4 // out // = '...'/'.'// Character used for ellipsis rendering.
|
||||
ImWchar FallbackChar; // 2-4 // out // = FFFD/'?' // Character used if a glyph isn't found.
|
||||
float EllipsisWidth; // 4 // out // Width
|
||||
float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0
|
||||
ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...').
|
||||
ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?')
|
||||
float EllipsisWidth; // 4 // out // Total ellipsis Width
|
||||
float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0
|
||||
float Scale; // 4 // in // Base font scale (1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale()
|
||||
float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled)
|
||||
int MetricsTotalSurface;// 4 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs)
|
||||
bool DirtyLookupTables; // 1 // out //
|
||||
float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale()
|
||||
float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled)
|
||||
int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs)
|
||||
ImU8 Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints.
|
||||
ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints.
|
||||
|
||||
// Methods
|
||||
IMGUI_API ImFont();
|
||||
IMGUI_API ~ImFont();
|
||||
IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c);
|
||||
IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c);
|
||||
float GetCharAdvance(ImWchar c) { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; }
|
||||
bool IsLoaded() const { return ContainerAtlas != NULL; }
|
||||
const char* GetDebugName() const { return ConfigData ? ConfigData->Name : "<unknown>"; }
|
||||
float GetCharAdvance(ImWchar c) { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; }
|
||||
bool IsLoaded() const { return ContainerAtlas != NULL; }
|
||||
const char* GetDebugName() const { return ConfigData ? ConfigData->Name : "<unknown>"; }
|
||||
|
||||
// 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable.
|
||||
// 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable.
|
||||
|
||||
28
3rdparty/imgui/include/imgui_internal.h
vendored
28
3rdparty/imgui/include/imgui_internal.h
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.7
|
||||
// dear imgui, v1.91.8
|
||||
// (internal structures/api)
|
||||
|
||||
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
|
||||
@@ -130,10 +130,17 @@ Index of this file:
|
||||
// [SECTION] Forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Utilities
|
||||
// (other types which are not forwarded declared are: ImBitArray<>, ImSpan<>, ImSpanAllocator<>, ImPool<>, ImChunkStream<>)
|
||||
struct ImBitVector; // Store 1-bit per value
|
||||
struct ImRect; // An axis-aligned rectangle (2 points)
|
||||
struct ImGuiTextIndex; // Maintain a line index for a text buffer.
|
||||
|
||||
// ImDrawList/ImFontAtlas
|
||||
struct ImDrawDataBuilder; // Helper to build a ImDrawData instance
|
||||
struct ImDrawListSharedData; // Data shared between all ImDrawList instances
|
||||
|
||||
// ImGui
|
||||
struct ImGuiBoxSelectState; // Box-selection state (currently used by multi-selection, could potentially be used by others)
|
||||
struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it
|
||||
struct ImGuiContext; // Main Dear ImGui context
|
||||
@@ -222,7 +229,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
|
||||
#endif
|
||||
|
||||
// Debug Logging for ShowDebugLogWindow(). This is designed for relatively rare events so please don't spam.
|
||||
#define IMGUI_DEBUG_LOG_ERROR(...) do { ImGuiContext& g2 = *GImGui; if (g2.DebugLogFlags & ImGuiDebugLogFlags_EventError) IMGUI_DEBUG_LOG(__VA_ARGS__); else g2.DebugLogSkippedErrors++; } while (0)
|
||||
#define IMGUI_DEBUG_LOG_ERROR(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventError) IMGUI_DEBUG_LOG(__VA_ARGS__); else g.DebugLogSkippedErrors++; } while (0)
|
||||
#define IMGUI_DEBUG_LOG_ACTIVEID(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventActiveId) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
|
||||
#define IMGUI_DEBUG_LOG_FOCUS(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
|
||||
#define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
|
||||
@@ -462,7 +469,7 @@ static inline double ImRsqrt(double x) { return 1.0 / sqrt(x); }
|
||||
template<typename T> static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; }
|
||||
template<typename T> static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; }
|
||||
template<typename T> static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }
|
||||
template<typename T> static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * (T)t); }
|
||||
template<typename T> static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); }
|
||||
template<typename T> static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; }
|
||||
template<typename T> static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; }
|
||||
template<typename T> static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; }
|
||||
@@ -736,6 +743,7 @@ struct ImGuiTextIndex
|
||||
|
||||
// Helper: ImGuiStorage
|
||||
IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStoragePair* in_end, ImGuiID key);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] ImDrawList support
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -2448,6 +2456,8 @@ struct IMGUI_API ImGuiWindowTempData
|
||||
ImGuiLayoutType LayoutType;
|
||||
ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin()
|
||||
ImU32 ModalDimBgColor;
|
||||
ImGuiItemStatusFlags WindowItemStatusFlags;
|
||||
ImGuiItemStatusFlags ChildItemStatusFlags;
|
||||
|
||||
// Local parameters stacks
|
||||
// We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings.
|
||||
@@ -2543,6 +2553,8 @@ struct IMGUI_API ImGuiWindow
|
||||
ImGuiStorage StateStorage;
|
||||
ImVector<ImGuiOldColumns> ColumnsStorage;
|
||||
float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale()
|
||||
float FontWindowScaleParents;
|
||||
float FontRefSize; // This is a copy of window->CalcFontSize() at the time of Begin(), trying to phase out CalcFontSize() especially as it may be called on non-current window.
|
||||
int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back)
|
||||
|
||||
ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer)
|
||||
@@ -2577,7 +2589,7 @@ public:
|
||||
|
||||
// We don't use g.FontSize because the window may be != g.CurrentWindow.
|
||||
ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
|
||||
float CalcFontSize() const { ImGuiContext& g = *Ctx; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; }
|
||||
float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontBaseSize * FontWindowScale * FontWindowScaleParents; }
|
||||
ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight)); }
|
||||
ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight; return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight); }
|
||||
};
|
||||
@@ -2600,6 +2612,8 @@ enum ImGuiTabItemFlagsPrivate_
|
||||
ImGuiTabItemFlags_SectionMask_ = ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing,
|
||||
ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout)
|
||||
ImGuiTabItemFlags_Button = 1 << 21, // Used by TabItemButton, change the tab item behavior to mimic a button
|
||||
ImGuiTabItemFlags_Invisible = 1 << 22, // To reserve space e.g. with ImGuiTabItemFlags_Leading
|
||||
//ImGuiTabItemFlags_Unsorted = 1 << 23, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window.
|
||||
};
|
||||
|
||||
// Storage for one active tab item (sizeof() 40 bytes)
|
||||
@@ -2863,6 +2877,7 @@ struct IMGUI_API ImGuiTable
|
||||
ImGuiTableDrawChannelIdx DummyDrawChannel; // Redirect non-visible columns here.
|
||||
ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; // For Selectable() and other widgets drawing across columns after the freezing line. Index within DrawSplitter.Channels[]
|
||||
ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen;
|
||||
ImS8 NavLayer; // ImGuiNavLayer at the time of BeginTable().
|
||||
bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row.
|
||||
bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow().
|
||||
bool IsInitializing;
|
||||
@@ -3004,6 +3019,7 @@ namespace ImGui
|
||||
// Fonts, drawing
|
||||
IMGUI_API void SetCurrentFont(ImFont* font);
|
||||
inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; }
|
||||
IMGUI_API void PushPasswordFont();
|
||||
inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches.
|
||||
IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents.
|
||||
IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents.
|
||||
@@ -3085,7 +3101,7 @@ namespace ImGui
|
||||
IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags);
|
||||
IMGUI_API bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags = 0);
|
||||
IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id);
|
||||
IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect);
|
||||
IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags item_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect);
|
||||
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h);
|
||||
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
|
||||
IMGUI_API void PushMultiItemsWidths(int components, float width_full);
|
||||
@@ -3366,6 +3382,7 @@ namespace ImGui
|
||||
IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImVec2 mouse_pos);
|
||||
IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar);
|
||||
IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window);
|
||||
IMGUI_API void TabItemSpacing(const char* str_id, ImGuiTabItemFlags flags, float width);
|
||||
IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker);
|
||||
IMGUI_API ImVec2 TabItemCalcSize(ImGuiWindow* window);
|
||||
IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col);
|
||||
@@ -3561,6 +3578,7 @@ IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas,
|
||||
IMGUI_API void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value);
|
||||
IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);
|
||||
IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);
|
||||
IMGUI_API void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Test Engine specific hooks (imgui_test_engine)
|
||||
|
||||
211
3rdparty/imgui/src/imgui.cpp
vendored
211
3rdparty/imgui/src/imgui.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.7
|
||||
// dear imgui, v1.91.8
|
||||
// (main code and documentation)
|
||||
|
||||
// Help:
|
||||
@@ -430,6 +430,9 @@ CODE
|
||||
When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
|
||||
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
|
||||
|
||||
- 2025/01/22 (1.91.8) - removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior.
|
||||
prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior.
|
||||
the new flags (ImGuiColorEditFlags_AlphaOpaque, ImGuiColorEditFlags_AlphaNoBg + existing ImGuiColorEditFlags_AlphaPreviewHalf) may be combined better and allow finer controls:
|
||||
- 2025/01/14 (1.91.7) - renamed ImGuiTreeNodeFlags_SpanTextWidth to ImGuiTreeNodeFlags_SpanLabelWidth for consistency with other names. Kept redirection enum (will obsolete). (#6937)
|
||||
- 2024/11/27 (1.91.6) - changed CRC32 table from CRC32-adler to CRC32c polynomial in order to be compatible with the result of SSE 4.2 instructions.
|
||||
As a result, old .ini data may be partially lost (docking and tables information particularly).
|
||||
@@ -1253,6 +1256,7 @@ static void RenderWindowTitleBarContents(ImGuiWindow* window, const
|
||||
static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col);
|
||||
static void RenderDimmedBackgrounds();
|
||||
static void SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect);
|
||||
static void SetLastItemDataForChildWindowItem(ImGuiWindow* window, const ImRect& rect);
|
||||
|
||||
// Viewports
|
||||
const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbitrary constant instead of e.g. ImHashStr("ViewportDefault", 0); so it's easier to spot in the debugger. The exact value doesn't matter.
|
||||
@@ -1334,11 +1338,11 @@ ImGuiStyle::ImGuiStyle()
|
||||
GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar
|
||||
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
|
||||
LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
|
||||
TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
|
||||
TabRounding = 5.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
|
||||
TabBorderSize = 0.0f; // Thickness of border around tabs.
|
||||
TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
|
||||
TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
|
||||
TabBarOverlineSize = 2.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar.
|
||||
TabBarOverlineSize = 1.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar.
|
||||
TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees).
|
||||
TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell
|
||||
ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
|
||||
@@ -4276,7 +4280,8 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NUL
|
||||
SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
|
||||
LastFrameActive = -1;
|
||||
LastTimeActive = -1.0f;
|
||||
FontWindowScale = 1.0f;
|
||||
FontRefSize = 0.0f;
|
||||
FontWindowScale = FontWindowScaleParents = 1.0f;
|
||||
SettingsOffset = -1;
|
||||
DrawList = &DrawListInst;
|
||||
DrawList->_OwnerName = Name;
|
||||
@@ -4691,15 +4696,27 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id)
|
||||
|
||||
// This is also inlined in ItemAdd()
|
||||
// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set g.LastItemData.DisplayRect.
|
||||
void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
|
||||
void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags item_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.LastItemData.ID = item_id;
|
||||
g.LastItemData.ItemFlags = in_flags;
|
||||
g.LastItemData.StatusFlags = item_flags;
|
||||
g.LastItemData.ItemFlags = item_flags;
|
||||
g.LastItemData.StatusFlags = status_flags;
|
||||
g.LastItemData.Rect = g.LastItemData.NavRect = item_rect;
|
||||
}
|
||||
|
||||
static void ImGui::SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
SetLastItemData(window->MoveId, g.CurrentItemFlags, window->DC.WindowItemStatusFlags, rect);
|
||||
}
|
||||
|
||||
static void ImGui::SetLastItemDataForChildWindowItem(ImGuiWindow* window, const ImRect& rect)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
SetLastItemData(window->ChildId, g.CurrentItemFlags, window->DC.ChildItemStatusFlags, rect);
|
||||
}
|
||||
|
||||
float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
|
||||
{
|
||||
if (wrap_pos_x < 0.0f)
|
||||
@@ -5086,6 +5103,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
|
||||
}
|
||||
|
||||
// Called once a frame. Followed by SetCurrentFont() which sets up the remaining data.
|
||||
// FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal!
|
||||
static void SetupDrawListSharedData()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@@ -6152,7 +6170,14 @@ void ImGui::EndChild()
|
||||
}
|
||||
if (g.HoveredWindow == child_window)
|
||||
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
|
||||
child_window->DC.ChildItemStatusFlags = g.LastItemData.StatusFlags;
|
||||
//SetLastItemDataForChildWindowItem(child_window, child_window->Rect()); // Not needed, effectively done by ItemAdd()
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastItemDataForChildWindowItem(child_window, child_window->Rect());
|
||||
}
|
||||
|
||||
g.WithinEndChildID = backup_within_end_child_id;
|
||||
g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
|
||||
}
|
||||
@@ -6707,7 +6732,7 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
|
||||
if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
|
||||
{
|
||||
float y = window->Pos.y + window->TitleBarHeight - 1;
|
||||
window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), border_col, g.Style.FrameBorderSize);
|
||||
window->DrawList->AddLine(ImVec2(window->Pos.x + border_size * 0.5f, y), ImVec2(window->Pos.x + window->Size.x - border_size * 0.5f, y), border_col, g.Style.FrameBorderSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6767,9 +6792,9 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
|
||||
{
|
||||
ImRect menu_bar_rect = window->MenuBarRect();
|
||||
menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
|
||||
window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop);
|
||||
window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop);
|
||||
if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
|
||||
window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
|
||||
window->DrawList->AddLine(menu_bar_rect.GetBL() + ImVec2(window_border_size * 0.5f, 0.0f), menu_bar_rect.GetBR() - ImVec2(window_border_size * 0.5f, 0.0f), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
|
||||
}
|
||||
|
||||
// Scrollbars
|
||||
@@ -6788,9 +6813,10 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
|
||||
continue;
|
||||
const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
|
||||
const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
|
||||
window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size)));
|
||||
window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size)));
|
||||
window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
|
||||
const float border_inner = IM_ROUND(window_border_size * 0.5f);
|
||||
window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(border_inner, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, border_inner)));
|
||||
window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, border_inner) : ImVec2(border_inner, resize_grip_draw_size)));
|
||||
window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + border_inner), corner.y + grip.InnerDir.y * (window_rounding + border_inner)), window_rounding, grip.AngleMin12, grip.AngleMax12);
|
||||
window->DrawList->PathFillConvex(col);
|
||||
}
|
||||
}
|
||||
@@ -7036,6 +7062,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
// There's little point to expose a flag to set this: because the interesting cases won't be using parent_window_in_stack,
|
||||
// e.g. linking a tool window in a standalone viewport to a document window, regardless of their Begin() stack parenting. (#6798)
|
||||
window->ParentWindowForFocusRoute = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window_in_stack : NULL;
|
||||
|
||||
// Inherent SetWindowFontScale() from parent until we fix this system...
|
||||
window->FontWindowScaleParents = parent_window ? parent_window->FontWindowScaleParents * parent_window->FontWindowScale : 1.0f;
|
||||
}
|
||||
|
||||
// Add to focus scope stack
|
||||
@@ -7197,6 +7226,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
|
||||
window->TitleBarHeight = (flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : g.FontSize + g.Style.FramePadding.y * 2.0f;
|
||||
window->MenuBarHeight = (flags & ImGuiWindowFlags_MenuBar) ? window->DC.MenuBarOffset.y + g.FontSize + g.Style.FramePadding.y * 2.0f : 0.0f;
|
||||
window->FontRefSize = g.FontSize; // Lock this to discourage calling window->CalcFontSize() outside of current window.
|
||||
|
||||
// Depending on condition we use previous or current window size to compare against contents size to decide if a scrollbar should be visible.
|
||||
// Those flags will be altered further down in the function depending on more conditions.
|
||||
@@ -7602,6 +7632,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
|
||||
// We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin().
|
||||
// This is useful to allow creating context menus on title bar only, etc.
|
||||
window->DC.WindowItemStatusFlags = ImGuiItemStatusFlags_None;
|
||||
window->DC.WindowItemStatusFlags |= IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0;
|
||||
SetLastItemDataForWindow(window, title_bar_rect);
|
||||
|
||||
// [DEBUG]
|
||||
@@ -7707,12 +7739,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
return !window->SkipItems;
|
||||
}
|
||||
|
||||
static void ImGui::SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(rect.Min, rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, rect);
|
||||
}
|
||||
|
||||
void ImGui::End()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@@ -9204,6 +9230,17 @@ bool ImGui::IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id)
|
||||
return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyReleased(MouseButtonToKey(button), owner_id)
|
||||
}
|
||||
|
||||
// Use if you absolutely need to distinguish single-click from double-click by introducing a delay.
|
||||
// Generally use with 'delay >= io.MouseDoubleClickTime' + combined with a 'io.MouseClickedLastCount == 1' test.
|
||||
// This is a very rarely used UI idiom, but some apps use this: e.g. MS Explorer single click on an icon to rename.
|
||||
bool ImGui::IsMouseReleasedWithDelay(ImGuiMouseButton button, float delay)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
|
||||
const float time_since_release = (float)(g.Time - g.IO.MouseReleasedTime[button]);
|
||||
return !IsMouseDown(button) && (time_since_release - g.IO.DeltaTime < delay) && (time_since_release >= delay);
|
||||
}
|
||||
|
||||
bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@@ -9477,6 +9514,8 @@ static void ImGui::UpdateMouseInputs()
|
||||
io.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f;
|
||||
io.MouseClickedCount[i] = 0; // Will be filled below
|
||||
io.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0f;
|
||||
if (io.MouseReleased[i])
|
||||
io.MouseReleasedTime[i] = g.Time;
|
||||
io.MouseDownDurationPrev[i] = io.MouseDownDuration[i];
|
||||
io.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0.0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f;
|
||||
if (io.MouseClicked[i])
|
||||
@@ -9645,7 +9684,7 @@ void ImGui::UpdateMouseWheel()
|
||||
{
|
||||
LockWheelingWindow(window, wheel.x);
|
||||
float max_step = window->InnerRect.GetWidth() * 0.67f;
|
||||
float scroll_step = ImTrunc(ImMin(2 * window->CalcFontSize(), max_step));
|
||||
float scroll_step = ImTrunc(ImMin(2 * window->FontRefSize, max_step));
|
||||
SetScrollX(window, window->Scroll.x - wheel.x * scroll_step);
|
||||
g.WheelingWindowScrolledFrame = g.FrameCount;
|
||||
}
|
||||
@@ -9653,7 +9692,7 @@ void ImGui::UpdateMouseWheel()
|
||||
{
|
||||
LockWheelingWindow(window, wheel.y);
|
||||
float max_step = window->InnerRect.GetHeight() * 0.67f;
|
||||
float scroll_step = ImTrunc(ImMin(5 * window->CalcFontSize(), max_step));
|
||||
float scroll_step = ImTrunc(ImMin(5 * window->FontRefSize, max_step));
|
||||
SetScrollY(window, window->Scroll.y - wheel.y * scroll_step);
|
||||
g.WheelingWindowScrolledFrame = g.FrameCount;
|
||||
}
|
||||
@@ -10262,6 +10301,11 @@ void ImGui::ErrorRecoveryTryToRecoverWindowState(const ImGuiErrorRecoveryStat
|
||||
IM_ASSERT_USER_ERROR(0, "Missing EndMultiSelect()");
|
||||
EndMultiSelect();
|
||||
}
|
||||
if (window->DC.MenuBarAppending) //-V1044
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(0, "Missing EndMenuBar()");
|
||||
EndMenuBar();
|
||||
}
|
||||
while (window->DC.TreeDepth > state_in->SizeOfTreeStack) //-V1044
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(0, "Missing TreePop()");
|
||||
@@ -12983,7 +13027,7 @@ static void ImGui::NavUpdate()
|
||||
{
|
||||
// *Fallback* manual-scroll with Nav directional keys when window has no navigable item
|
||||
ImGuiWindow* window = g.NavWindow;
|
||||
const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
|
||||
const float scroll_speed = IM_ROUND(window->FontRefSize * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
|
||||
const ImGuiDir move_dir = g.NavMoveDir;
|
||||
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY && move_dir != ImGuiDir_None)
|
||||
{
|
||||
@@ -13173,8 +13217,8 @@ void ImGui::NavUpdateCreateMoveRequest()
|
||||
if ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
|
||||
{
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n");
|
||||
float pad_x = ImMin(inner_rect_rel.GetWidth(), window->CalcFontSize() * 0.5f);
|
||||
float pad_y = ImMin(inner_rect_rel.GetHeight(), window->CalcFontSize() * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item
|
||||
float pad_x = ImMin(inner_rect_rel.GetWidth(), window->FontRefSize * 0.5f);
|
||||
float pad_y = ImMin(inner_rect_rel.GetHeight(), window->FontRefSize * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item
|
||||
inner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -FLT_MAX;
|
||||
inner_rect_rel.Max.x = clamp_x ? (inner_rect_rel.Max.x - pad_x) : +FLT_MAX;
|
||||
inner_rect_rel.Min.y = clamp_y ? (inner_rect_rel.Min.y + pad_y) : -FLT_MAX;
|
||||
@@ -13432,7 +13476,7 @@ static float ImGui::NavUpdatePageUpPageDown()
|
||||
else
|
||||
{
|
||||
ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
|
||||
const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
|
||||
const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->FontRefSize * 1.0f + nav_rect_rel.GetHeight());
|
||||
float nav_scoring_rect_offset_y = 0.0f;
|
||||
if (IsKeyPressed(ImGuiKey_PageUp, true))
|
||||
{
|
||||
@@ -13813,12 +13857,12 @@ void ImGui::NavUpdateWindowingOverlay()
|
||||
return;
|
||||
|
||||
if (g.NavWindowingListWindow == NULL)
|
||||
g.NavWindowingListWindow = FindWindowByName("###NavWindowingList");
|
||||
g.NavWindowingListWindow = FindWindowByName("###NavWindowingOverlay");
|
||||
const ImGuiViewport* viewport = GetMainViewport();
|
||||
SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX));
|
||||
SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f);
|
||||
Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
|
||||
Begin("###NavWindowingOverlay", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
|
||||
if (g.ContextName[0] != 0)
|
||||
SeparatorText(g.ContextName);
|
||||
for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
|
||||
@@ -16128,18 +16172,24 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co
|
||||
// [DEBUG] Display details for a single font, called by ShowStyleEditor().
|
||||
void ImGui::DebugNodeFont(ImFont* font)
|
||||
{
|
||||
bool opened = TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)",
|
||||
bool opened = TreeNode(font, "Font: \"%s\": %.2f px, %d glyphs, %d sources(s)",
|
||||
font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount);
|
||||
SameLine();
|
||||
if (SmallButton("Set as default"))
|
||||
GetIO().FontDefault = font;
|
||||
if (!opened)
|
||||
return;
|
||||
|
||||
// Display preview text
|
||||
if (!opened)
|
||||
Indent();
|
||||
Indent();
|
||||
PushFont(font);
|
||||
Text("The quick brown fox jumps over the lazy dog");
|
||||
PopFont();
|
||||
if (!opened)
|
||||
{
|
||||
Unindent();
|
||||
Unindent();
|
||||
return;
|
||||
}
|
||||
if (SmallButton("Set as default"))
|
||||
GetIO().FontDefault = font;
|
||||
|
||||
// Display details
|
||||
SetNextItemWidth(GetFontSize() * 8);
|
||||
@@ -16158,62 +16208,69 @@ void ImGui::DebugNodeFont(ImFont* font)
|
||||
Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt);
|
||||
for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
|
||||
if (font->ConfigData)
|
||||
if (const ImFontConfig* cfg = &font->ConfigData[config_i])
|
||||
BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)",
|
||||
config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y);
|
||||
{
|
||||
const ImFontConfig* cfg = &font->ConfigData[config_i];
|
||||
int oversample_h, oversample_v;
|
||||
ImFontAtlasBuildGetOversampleFactors(cfg, &oversample_h, &oversample_v);
|
||||
BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)",
|
||||
config_i, cfg->Name, cfg->OversampleH, oversample_h, cfg->OversampleV, oversample_v, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y);
|
||||
}
|
||||
|
||||
// Display all glyphs of the fonts in separate pages of 256 characters
|
||||
if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
|
||||
{
|
||||
ImDrawList* draw_list = GetWindowDrawList();
|
||||
const ImU32 glyph_col = GetColorU32(ImGuiCol_Text);
|
||||
const float cell_size = font->FontSize * 1;
|
||||
const float cell_spacing = GetStyle().ItemSpacing.y;
|
||||
for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
|
||||
if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
|
||||
{
|
||||
// Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k)
|
||||
// This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT
|
||||
// is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here)
|
||||
if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095))
|
||||
ImDrawList* draw_list = GetWindowDrawList();
|
||||
const ImU32 glyph_col = GetColorU32(ImGuiCol_Text);
|
||||
const float cell_size = font->FontSize * 1;
|
||||
const float cell_spacing = GetStyle().ItemSpacing.y;
|
||||
for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
|
||||
{
|
||||
base += 4096 - 256;
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (unsigned int n = 0; n < 256; n++)
|
||||
if (font->FindGlyphNoFallback((ImWchar)(base + n)))
|
||||
count++;
|
||||
if (count <= 0)
|
||||
continue;
|
||||
if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
|
||||
continue;
|
||||
|
||||
// Draw a 16x16 grid of glyphs
|
||||
ImVec2 base_pos = GetCursorScreenPos();
|
||||
for (unsigned int n = 0; n < 256; n++)
|
||||
{
|
||||
// We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions
|
||||
// available here and thus cannot easily generate a zero-terminated UTF-8 encoded string.
|
||||
ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
|
||||
ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
|
||||
const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));
|
||||
draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
|
||||
if (!glyph)
|
||||
continue;
|
||||
font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n));
|
||||
if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip())
|
||||
// Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k)
|
||||
// This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT
|
||||
// is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here)
|
||||
if (!(base & 8191) && font->IsGlyphRangeUnused(base, base + 8191))
|
||||
{
|
||||
DebugNodeFontGlyph(font, glyph);
|
||||
EndTooltip();
|
||||
base += 8192 - 256;
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (unsigned int n = 0; n < 256; n++)
|
||||
if (font->FindGlyphNoFallback((ImWchar)(base + n)))
|
||||
count++;
|
||||
if (count <= 0)
|
||||
continue;
|
||||
if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
|
||||
continue;
|
||||
|
||||
// Draw a 16x16 grid of glyphs
|
||||
ImVec2 base_pos = GetCursorScreenPos();
|
||||
for (unsigned int n = 0; n < 256; n++)
|
||||
{
|
||||
// We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions
|
||||
// available here and thus cannot easily generate a zero-terminated UTF-8 encoded string.
|
||||
ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
|
||||
ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
|
||||
const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));
|
||||
draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
|
||||
if (!glyph)
|
||||
continue;
|
||||
font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n));
|
||||
if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip())
|
||||
{
|
||||
DebugNodeFontGlyph(font, glyph);
|
||||
EndTooltip();
|
||||
}
|
||||
}
|
||||
Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
|
||||
TreePop();
|
||||
}
|
||||
Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
|
||||
TreePop();
|
||||
}
|
||||
TreePop();
|
||||
}
|
||||
TreePop();
|
||||
Unindent();
|
||||
}
|
||||
|
||||
void ImGui::DebugNodeFontGlyph(ImFont*, const ImFontGlyph* glyph)
|
||||
|
||||
78
3rdparty/imgui/src/imgui_demo.cpp
vendored
78
3rdparty/imgui/src/imgui_demo.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.7
|
||||
// dear imgui, v1.91.8
|
||||
// (demo code)
|
||||
|
||||
// Help:
|
||||
@@ -2117,19 +2117,16 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
|
||||
if (ImGui::TreeNode("Color/Picker Widgets"))
|
||||
{
|
||||
static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
|
||||
static ImGuiColorEditFlags base_flags = ImGuiColorEditFlags_None;
|
||||
|
||||
static bool alpha_preview = true;
|
||||
static bool alpha_half_preview = false;
|
||||
static bool drag_and_drop = true;
|
||||
static bool options_menu = true;
|
||||
static bool hdr = false;
|
||||
ImGui::SeparatorText("Options");
|
||||
ImGui::Checkbox("With Alpha Preview", &alpha_preview);
|
||||
ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
|
||||
ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
|
||||
ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
|
||||
ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
|
||||
ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions);
|
||||
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &base_flags, ImGuiColorEditFlags_NoAlpha);
|
||||
ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", &base_flags, ImGuiColorEditFlags_AlphaOpaque);
|
||||
ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", &base_flags, ImGuiColorEditFlags_AlphaNoBg);
|
||||
ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", &base_flags, ImGuiColorEditFlags_AlphaPreviewHalf);
|
||||
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", &base_flags, ImGuiColorEditFlags_NoDragDrop);
|
||||
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoOptions", &base_flags, ImGuiColorEditFlags_NoOptions); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
|
||||
ImGui::CheckboxFlags("ImGuiColorEditFlags_HDR", &base_flags, ImGuiColorEditFlags_HDR); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit");
|
||||
ImGui::SeparatorText("Inline color editor");
|
||||
@@ -2137,15 +2134,15 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
|
||||
ImGui::SameLine(); HelpMarker(
|
||||
"Click on the color square to open a color picker.\n"
|
||||
"CTRL+click on individual component to input value.\n");
|
||||
ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
|
||||
ImGui::ColorEdit3("MyColor##1", (float*)&color, base_flags);
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)");
|
||||
ImGui::Text("Color widget HSV with Alpha:");
|
||||
ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags);
|
||||
ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | base_flags);
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)");
|
||||
ImGui::Text("Color widget with Float Display:");
|
||||
ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
|
||||
ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | base_flags);
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)");
|
||||
ImGui::Text("Color button with Picker:");
|
||||
@@ -2153,7 +2150,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
|
||||
"With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
|
||||
"With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
|
||||
"be used for the tooltip and picker popup.");
|
||||
ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
|
||||
ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | base_flags);
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)");
|
||||
ImGui::Text("Color button with Custom Picker Popup:");
|
||||
@@ -2173,7 +2170,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
|
||||
}
|
||||
|
||||
static ImVec4 backup_color;
|
||||
bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
|
||||
bool open_popup = ImGui::ColorButton("MyColor##3b", color, base_flags);
|
||||
ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
open_popup |= ImGui::Button("Palette");
|
||||
if (open_popup)
|
||||
@@ -2185,7 +2182,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
|
||||
{
|
||||
ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
|
||||
ImGui::Separator();
|
||||
ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
|
||||
ImGui::ColorPicker4("##picker", (float*)&color, base_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::BeginGroup(); // Lock X position
|
||||
@@ -2227,40 +2224,42 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
|
||||
ImGui::Text("Color button only:");
|
||||
static bool no_border = false;
|
||||
ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
|
||||
ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
|
||||
ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker");
|
||||
ImGui::SeparatorText("Color picker");
|
||||
static bool alpha = true;
|
||||
static bool alpha_bar = true;
|
||||
static bool side_preview = true;
|
||||
|
||||
static bool ref_color = false;
|
||||
static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
|
||||
static int display_mode = 0;
|
||||
static int picker_mode = 0;
|
||||
ImGui::Checkbox("With Alpha", &alpha);
|
||||
ImGui::Checkbox("With Alpha Bar", &alpha_bar);
|
||||
ImGui::Checkbox("With Side Preview", &side_preview);
|
||||
if (side_preview)
|
||||
static int display_mode = 0;
|
||||
static ImGuiColorEditFlags color_picker_flags = ImGuiColorEditFlags_AlphaBar;
|
||||
|
||||
ImGui::PushID("Color picker");
|
||||
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &color_picker_flags, ImGuiColorEditFlags_NoAlpha);
|
||||
ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaBar", &color_picker_flags, ImGuiColorEditFlags_AlphaBar);
|
||||
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", &color_picker_flags, ImGuiColorEditFlags_NoSidePreview);
|
||||
if (color_picker_flags & ImGuiColorEditFlags_NoSidePreview)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("With Ref Color", &ref_color);
|
||||
if (ref_color)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
|
||||
ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | base_flags);
|
||||
}
|
||||
}
|
||||
ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0");
|
||||
|
||||
ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0");
|
||||
ImGui::SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode.");
|
||||
|
||||
ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0");
|
||||
ImGui::SameLine(); HelpMarker(
|
||||
"ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
|
||||
"but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
|
||||
"if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
|
||||
ImGui::SameLine(); HelpMarker("When not specified explicitly (Auto/Current mode), user can right-click the picker to change mode.");
|
||||
ImGuiColorEditFlags flags = misc_flags;
|
||||
if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
|
||||
if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
|
||||
if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
|
||||
|
||||
ImGuiColorEditFlags flags = base_flags | color_picker_flags;
|
||||
if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
|
||||
if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
|
||||
if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays
|
||||
@@ -2289,6 +2288,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(w);
|
||||
ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
|
||||
ImGui::PopID();
|
||||
|
||||
// HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
|
||||
static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
|
||||
@@ -7408,6 +7408,8 @@ static void ShowDemoWindowInputs()
|
||||
ImGui::Text("Mouse down:");
|
||||
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
|
||||
ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
|
||||
ImGui::Text("Mouse clicked count:");
|
||||
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseClickedCount[i] > 0) { ImGui::SameLine(); ImGui::Text("b%d: %d", i, io.MouseClickedCount[i]); }
|
||||
|
||||
// We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows
|
||||
// displaying the data for old/new backends.
|
||||
@@ -7966,7 +7968,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
|
||||
ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f");
|
||||
ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 2.0f, "%.0f");
|
||||
ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 3.0f, "%.0f");
|
||||
ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.");
|
||||
|
||||
ImGui::SeparatorText("Rounding");
|
||||
@@ -8046,9 +8048,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
|
||||
filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
|
||||
|
||||
static ImGuiColorEditFlags alpha_flags = 0;
|
||||
if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
|
||||
HelpMarker(
|
||||
"In the color list:\n"
|
||||
"Left-click on color square to open color picker,\n"
|
||||
|
||||
83
3rdparty/imgui/src/imgui_draw.cpp
vendored
83
3rdparty/imgui/src/imgui_draw.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.7
|
||||
// dear imgui, v1.91.8
|
||||
// (drawing and font code)
|
||||
|
||||
/*
|
||||
@@ -1669,8 +1669,7 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32
|
||||
// Accept null ranges
|
||||
if (text_begin == text_end || text_begin[0] == 0)
|
||||
return;
|
||||
if (text_end == NULL)
|
||||
text_end = text_begin + strlen(text_begin);
|
||||
// No need to strlen() here: font->RenderText() will do it and may early out.
|
||||
|
||||
// Pull default font/size from the shared ImDrawListSharedData instance
|
||||
if (font == NULL)
|
||||
@@ -1693,7 +1692,7 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32
|
||||
|
||||
void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
|
||||
{
|
||||
AddText(NULL, 0.0f, pos, col, text_begin, text_end);
|
||||
AddText(_Data->Font, _Data->FontSize, pos, col, text_begin, text_end);
|
||||
}
|
||||
|
||||
void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col)
|
||||
@@ -2375,8 +2374,8 @@ ImFontConfig::ImFontConfig()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
FontDataOwnedByAtlas = true;
|
||||
OversampleH = 2;
|
||||
OversampleV = 1;
|
||||
OversampleH = 0; // Auto == 1 or 2 depending on size
|
||||
OversampleV = 0; // Auto == 1
|
||||
GlyphMaxAdvanceX = FLT_MAX;
|
||||
RasterizerMultiply = 1.0f;
|
||||
RasterizerDensity = 1.0f;
|
||||
@@ -2521,6 +2520,7 @@ void ImFontAtlas::ClearTexData()
|
||||
void ImFontAtlas::ClearFonts()
|
||||
{
|
||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||
ClearInputData();
|
||||
Fonts.clear_delete();
|
||||
TexReady = false;
|
||||
}
|
||||
@@ -2573,8 +2573,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
|
||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||
IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
|
||||
IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?");
|
||||
IM_ASSERT(font_cfg->OversampleH > 0 && font_cfg->OversampleV > 0 && "Is ImFontConfig struct correctly initialized?");
|
||||
IM_ASSERT(font_cfg->RasterizerDensity > 0.0f);
|
||||
IM_ASSERT(font_cfg->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?");
|
||||
|
||||
// Create new font
|
||||
if (!font_cfg->MergeMode)
|
||||
@@ -2820,6 +2819,13 @@ void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig
|
||||
*data = table[*data];
|
||||
}
|
||||
|
||||
void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v)
|
||||
{
|
||||
// Automatically disable horizontal oversampling over size 36
|
||||
*out_oversample_h = (cfg->OversampleH != 0) ? cfg->OversampleH : (cfg->SizePixels * cfg->RasterizerDensity > 36.0f || cfg->PixelSnapH) ? 1 : 2;
|
||||
*out_oversample_v = (cfg->OversampleV != 0) ? cfg->OversampleV : 1;
|
||||
}
|
||||
|
||||
#ifdef IMGUI_ENABLE_STB_TRUETYPE
|
||||
// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont)
|
||||
// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.)
|
||||
@@ -2985,15 +2991,19 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
buf_rects_out_n += src_tmp.GlyphsCount;
|
||||
buf_packedchars_out_n += src_tmp.GlyphsCount;
|
||||
|
||||
// Convert our ranges in the format stb_truetype wants
|
||||
// Automatic selection of oversampling parameters
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
int oversample_h, oversample_v;
|
||||
ImFontAtlasBuildGetOversampleFactors(&cfg, &oversample_h, &oversample_v);
|
||||
|
||||
// Convert our ranges in the format stb_truetype wants
|
||||
src_tmp.PackRange.font_size = cfg.SizePixels * cfg.RasterizerDensity;
|
||||
src_tmp.PackRange.first_unicode_codepoint_in_range = 0;
|
||||
src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data;
|
||||
src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size;
|
||||
src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars;
|
||||
src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH;
|
||||
src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV;
|
||||
src_tmp.PackRange.h_oversample = (unsigned char)oversample_h;
|
||||
src_tmp.PackRange.v_oversample = (unsigned char)oversample_v;
|
||||
|
||||
// Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)
|
||||
const float scale = (cfg.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels * cfg.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels * cfg.RasterizerDensity);
|
||||
@@ -3002,9 +3012,9 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
int x0, y0, x1, y1;
|
||||
const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]);
|
||||
IM_ASSERT(glyph_index_in_font != 0);
|
||||
stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1);
|
||||
src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + pack_padding + cfg.OversampleH - 1);
|
||||
src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + pack_padding + cfg.OversampleV - 1);
|
||||
stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * oversample_h, scale * oversample_v, 0, 0, &x0, &y0, &x1, &y1);
|
||||
src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + pack_padding + oversample_h - 1);
|
||||
src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + pack_padding + oversample_v - 1);
|
||||
total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
|
||||
}
|
||||
}
|
||||
@@ -3689,7 +3699,7 @@ ImFont::ImFont()
|
||||
Scale = 1.0f;
|
||||
Ascent = Descent = 0.0f;
|
||||
MetricsTotalSurface = 0;
|
||||
memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
|
||||
memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap));
|
||||
}
|
||||
|
||||
ImFont::~ImFont()
|
||||
@@ -3709,7 +3719,7 @@ void ImFont::ClearOutputData()
|
||||
DirtyLookupTables = true;
|
||||
Ascent = Descent = 0.0f;
|
||||
MetricsTotalSurface = 0;
|
||||
memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
|
||||
memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap));
|
||||
}
|
||||
|
||||
static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count)
|
||||
@@ -3732,17 +3742,17 @@ void ImFont::BuildLookupTable()
|
||||
IndexAdvanceX.clear();
|
||||
IndexLookup.clear();
|
||||
DirtyLookupTables = false;
|
||||
memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
|
||||
memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap));
|
||||
GrowIndex(max_codepoint + 1);
|
||||
for (int i = 0; i < Glyphs.Size; i++)
|
||||
{
|
||||
int codepoint = (int)Glyphs[i].Codepoint;
|
||||
IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
|
||||
IndexLookup[codepoint] = (ImWchar)i;
|
||||
IndexLookup[codepoint] = (ImU16)i;
|
||||
|
||||
// Mark 4K page as used
|
||||
const int page_n = codepoint / 4096;
|
||||
Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7);
|
||||
const int page_n = codepoint / 8192;
|
||||
Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7);
|
||||
}
|
||||
|
||||
// Create a glyph to handle TAB
|
||||
@@ -3756,7 +3766,7 @@ void ImFont::BuildLookupTable()
|
||||
tab_glyph.Codepoint = '\t';
|
||||
tab_glyph.AdvanceX *= IM_TABSIZE;
|
||||
IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX;
|
||||
IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size - 1);
|
||||
IndexLookup[(int)tab_glyph.Codepoint] = (ImU16)(Glyphs.Size - 1);
|
||||
}
|
||||
|
||||
// Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons)
|
||||
@@ -3804,15 +3814,15 @@ void ImFont::BuildLookupTable()
|
||||
}
|
||||
}
|
||||
|
||||
// API is designed this way to avoid exposing the 4K page size
|
||||
// API is designed this way to avoid exposing the 8K page size
|
||||
// e.g. use with IsGlyphRangeUnused(0, 255)
|
||||
bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
|
||||
{
|
||||
unsigned int page_begin = (c_begin / 4096);
|
||||
unsigned int page_last = (c_last / 4096);
|
||||
unsigned int page_begin = (c_begin / 8192);
|
||||
unsigned int page_last = (c_last / 8192);
|
||||
for (unsigned int page_n = page_begin; page_n <= page_last; page_n++)
|
||||
if ((page_n >> 3) < sizeof(Used4kPagesMap))
|
||||
if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7)))
|
||||
if ((page_n >> 3) < sizeof(Used8kPagesMap))
|
||||
if (Used8kPagesMap[page_n >> 3] & (1 << (page_n & 7)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -3829,7 +3839,7 @@ void ImFont::GrowIndex(int new_size)
|
||||
if (new_size <= IndexLookup.Size)
|
||||
return;
|
||||
IndexAdvanceX.resize(new_size, -1.0f);
|
||||
IndexLookup.resize(new_size, (ImWchar)-1);
|
||||
IndexLookup.resize(new_size, (ImU16)-1);
|
||||
}
|
||||
|
||||
// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
|
||||
@@ -3872,6 +3882,7 @@ void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, floa
|
||||
glyph.U1 = u1;
|
||||
glyph.V1 = v1;
|
||||
glyph.AdvanceX = advance_x;
|
||||
IM_ASSERT(Glyphs.Size < 0xFFFF); // IndexLookup[] hold 16-bit values and -1 is reserved.
|
||||
|
||||
// Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round)
|
||||
// We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling.
|
||||
@@ -3885,13 +3896,13 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
|
||||
IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
|
||||
unsigned int index_size = (unsigned int)IndexLookup.Size;
|
||||
|
||||
if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists
|
||||
if (dst < index_size && IndexLookup.Data[dst] == (ImU16)-1 && !overwrite_dst) // 'dst' already exists
|
||||
return;
|
||||
if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op
|
||||
return;
|
||||
|
||||
GrowIndex(dst + 1);
|
||||
IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1;
|
||||
IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImU16)-1;
|
||||
IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;
|
||||
}
|
||||
|
||||
@@ -3900,8 +3911,8 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c)
|
||||
{
|
||||
if (c >= (size_t)IndexLookup.Size)
|
||||
return FallbackGlyph;
|
||||
const ImWchar i = IndexLookup.Data[c];
|
||||
if (i == (ImWchar)-1)
|
||||
const ImU16 i = IndexLookup.Data[c];
|
||||
if (i == (ImU16)-1)
|
||||
return FallbackGlyph;
|
||||
return &Glyphs.Data[i];
|
||||
}
|
||||
@@ -3910,8 +3921,8 @@ const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c)
|
||||
{
|
||||
if (c >= (size_t)IndexLookup.Size)
|
||||
return NULL;
|
||||
const ImWchar i = IndexLookup.Data[c];
|
||||
if (i == (ImWchar)-1)
|
||||
const ImU16 i = IndexLookup.Data[c];
|
||||
if (i == (ImU16)-1)
|
||||
return NULL;
|
||||
return &Glyphs.Data[i];
|
||||
}
|
||||
@@ -4125,15 +4136,15 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
|
||||
void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip)
|
||||
{
|
||||
if (!text_end)
|
||||
text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
|
||||
|
||||
// Align to be pixel perfect
|
||||
float x = IM_TRUNC(pos.x);
|
||||
float y = IM_TRUNC(pos.y);
|
||||
if (y > clip_rect.w)
|
||||
return;
|
||||
|
||||
if (!text_end)
|
||||
text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
|
||||
|
||||
const float scale = size / FontSize;
|
||||
const float line_height = FontSize * scale;
|
||||
const float origin_x = x;
|
||||
|
||||
10
3rdparty/imgui/src/imgui_freetype.cpp
vendored
10
3rdparty/imgui/src/imgui_freetype.cpp
vendored
@@ -33,7 +33,7 @@
|
||||
// - For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
|
||||
// - The default dear imgui styles will be impacted by this change (alpha values will need tweaking).
|
||||
|
||||
// FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer).
|
||||
// FIXME: cfg.OversampleH, OversampleV are not supported, but generally not necessary with this rasterizer because Hinting makes everything look better.
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DISABLE
|
||||
@@ -104,6 +104,9 @@ static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_
|
||||
// Code
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#define FT_CEIL(X) (((X + 63) & -64) / 64) // From SDL_ttf: Handy routines for converting from fixed point
|
||||
#define FT_SCALEFACTOR 64.0f
|
||||
|
||||
namespace
|
||||
{
|
||||
// Glyph metrics:
|
||||
@@ -182,9 +185,6 @@ namespace
|
||||
float InvRasterizationDensity;
|
||||
};
|
||||
|
||||
// From SDL_ttf: Handy routines for converting from fixed point
|
||||
#define FT_CEIL(X) (((X + 63) & -64) / 64)
|
||||
|
||||
bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_font_builder_flags)
|
||||
{
|
||||
FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face);
|
||||
@@ -316,7 +316,7 @@ namespace
|
||||
out_glyph_info->Height = (int)ft_bitmap->rows;
|
||||
out_glyph_info->OffsetX = Face->glyph->bitmap_left;
|
||||
out_glyph_info->OffsetY = -Face->glyph->bitmap_top;
|
||||
out_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x);
|
||||
out_glyph_info->AdvanceX = (float)slot->advance.x / FT_SCALEFACTOR;
|
||||
out_glyph_info->IsColored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA);
|
||||
|
||||
return ft_bitmap;
|
||||
|
||||
10
3rdparty/imgui/src/imgui_tables.cpp
vendored
10
3rdparty/imgui/src/imgui_tables.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.7
|
||||
// dear imgui, v1.91.8
|
||||
// (tables and columns code)
|
||||
|
||||
/*
|
||||
@@ -374,6 +374,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
table->ColumnsCount = columns_count;
|
||||
table->IsLayoutLocked = false;
|
||||
table->InnerWidth = inner_width;
|
||||
table->NavLayer = (ImS8)outer_window->DC.NavLayerCurrent;
|
||||
temp_data->UserOuterSize = outer_size;
|
||||
|
||||
// Instance data (for instance 0, TableID == TableInstanceID)
|
||||
@@ -1050,7 +1051,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
const int column_n = table->DisplayOrderToIndex[order_n];
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
|
||||
column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); // Use Count NOT request so Header line changes layer when frozen
|
||||
// Initial nav layer: using FreezeRowsCount, NOT FreezeRowsRequest, so Header line changes layer when frozen
|
||||
column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : (ImGuiNavLayer)table->NavLayer);
|
||||
|
||||
if (offset_x_frozen && table->FreezeColumnsCount == visible_n)
|
||||
{
|
||||
@@ -1493,7 +1495,7 @@ void ImGui::EndTable()
|
||||
if (inner_window != outer_window)
|
||||
{
|
||||
short backup_nav_layers_active_mask = inner_window->DC.NavLayersActiveMask;
|
||||
inner_window->DC.NavLayersActiveMask |= 1 << ImGuiNavLayer_Main; // So empty table don't appear to navigate differently.
|
||||
inner_window->DC.NavLayersActiveMask |= 1 << table->NavLayer; // So empty table don't appear to navigate differently.
|
||||
g.CurrentTable = NULL; // To avoid error recovery recursing
|
||||
EndChild();
|
||||
g.CurrentTable = table;
|
||||
@@ -2032,7 +2034,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
|
||||
if (unfreeze_rows_request)
|
||||
{
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main;
|
||||
table->Columns[column_n].NavLayerCurrent = table->NavLayer;
|
||||
const float y0 = ImMax(table->RowPosY2 + 1, table->InnerClipRect.Min.y);
|
||||
table_instance->LastFrozenHeight = y0 - table->OuterRect.Min.y;
|
||||
|
||||
|
||||
217
3rdparty/imgui/src/imgui_widgets.cpp
vendored
217
3rdparty/imgui/src/imgui_widgets.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.7
|
||||
// dear imgui, v1.91.8
|
||||
// (widgets code)
|
||||
|
||||
/*
|
||||
@@ -909,15 +909,17 @@ ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis)
|
||||
// Return scrollbar rectangle, must only be called for corresponding axis if window->ScrollbarX/Y is set.
|
||||
ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
const ImRect outer_rect = window->Rect();
|
||||
const ImRect inner_rect = window->InnerRect;
|
||||
const float border_size = window->WindowBorderSize;
|
||||
const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar)
|
||||
IM_ASSERT(scrollbar_size > 0.0f);
|
||||
const float border_size = IM_ROUND(window->WindowBorderSize * 0.5f);
|
||||
const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(g.Style.FrameBorderSize * 0.5f) : 0.0f;
|
||||
if (axis == ImGuiAxis_X)
|
||||
return ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size);
|
||||
return ImRect(inner_rect.Min.x + border_size, ImMax(outer_rect.Min.y + border_size, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size);
|
||||
else
|
||||
return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size);
|
||||
return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y + border_top, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size);
|
||||
}
|
||||
|
||||
void ImGui::Scrollbar(ImGuiAxis axis)
|
||||
@@ -4244,6 +4246,23 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
|
||||
BufTextLen += new_text_len;
|
||||
}
|
||||
|
||||
void ImGui::PushPasswordFont()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImFont* in_font = g.Font;
|
||||
ImFont* out_font = &g.InputTextPasswordFont;
|
||||
const ImFontGlyph* glyph = in_font->FindGlyph('*');
|
||||
out_font->FontSize = in_font->FontSize;
|
||||
out_font->Scale = in_font->Scale;
|
||||
out_font->Ascent = in_font->Ascent;
|
||||
out_font->Descent = in_font->Descent;
|
||||
out_font->ContainerAtlas = in_font->ContainerAtlas;
|
||||
out_font->FallbackGlyph = glyph;
|
||||
out_font->FallbackAdvanceX = glyph->AdvanceX;
|
||||
IM_ASSERT(out_font->Glyphs.Size == 0 && out_font->IndexAdvanceX.Size == 0 && out_font->IndexLookup.Size == 0);
|
||||
PushFont(out_font);
|
||||
}
|
||||
|
||||
// Return false to discard a character.
|
||||
static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard)
|
||||
{
|
||||
@@ -4654,19 +4673,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
// Password pushes a temporary font with only a fallback glyph
|
||||
if (is_password && !is_displaying_hint)
|
||||
{
|
||||
const ImFontGlyph* glyph = g.Font->FindGlyph('*');
|
||||
ImFont* password_font = &g.InputTextPasswordFont;
|
||||
password_font->FontSize = g.Font->FontSize;
|
||||
password_font->Scale = g.Font->Scale;
|
||||
password_font->Ascent = g.Font->Ascent;
|
||||
password_font->Descent = g.Font->Descent;
|
||||
password_font->ContainerAtlas = g.Font->ContainerAtlas;
|
||||
password_font->FallbackGlyph = glyph;
|
||||
password_font->FallbackAdvanceX = glyph->AdvanceX;
|
||||
IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty());
|
||||
PushFont(password_font);
|
||||
}
|
||||
PushPasswordFont();
|
||||
|
||||
// Process mouse inputs and character inputs
|
||||
if (g.ActiveId == id)
|
||||
@@ -5902,7 +5909,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
|
||||
if ((flags & ImGuiColorEditFlags_NoLabel))
|
||||
Text("Current");
|
||||
|
||||
ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip;
|
||||
ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaMask_ | ImGuiColorEditFlags_NoTooltip;
|
||||
ColorButton("##current", col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2));
|
||||
if (ref_col != NULL)
|
||||
{
|
||||
@@ -5942,7 +5949,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
|
||||
if ((flags & ImGuiColorEditFlags_NoInputs) == 0)
|
||||
{
|
||||
PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x);
|
||||
ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf;
|
||||
ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaMask_ | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSmallPreview;
|
||||
ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker;
|
||||
if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags_DisplayMask_) == 0)
|
||||
if (ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_DisplayRGB))
|
||||
@@ -6118,8 +6125,8 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held);
|
||||
|
||||
if (flags & ImGuiColorEditFlags_NoAlpha)
|
||||
flags &= ~(ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf);
|
||||
if (flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaOpaque))
|
||||
flags &= ~(ImGuiColorEditFlags_AlphaNoBg | ImGuiColorEditFlags_AlphaPreviewHalf);
|
||||
|
||||
ImVec4 col_rgb = col;
|
||||
if (flags & ImGuiColorEditFlags_InputHSV)
|
||||
@@ -6138,14 +6145,17 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
|
||||
if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f)
|
||||
{
|
||||
float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f);
|
||||
RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight);
|
||||
if ((flags & ImGuiColorEditFlags_AlphaNoBg) == 0)
|
||||
RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight);
|
||||
else
|
||||
window->DrawList->AddRectFilled(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), rounding, ImDrawFlags_RoundCornersRight);
|
||||
window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundCornersLeft);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha
|
||||
ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col_rgb : col_rgb_without_alpha;
|
||||
if (col_source.w < 1.0f)
|
||||
ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaOpaque) ? col_rgb_without_alpha : col_rgb;
|
||||
if (col_source.w < 1.0f && (flags & ImGuiColorEditFlags_AlphaNoBg) == 0)
|
||||
RenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding);
|
||||
else
|
||||
window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding);
|
||||
@@ -6175,7 +6185,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
|
||||
|
||||
// Tooltip
|
||||
if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered && IsItemHovered(ImGuiHoveredFlags_ForTooltip))
|
||||
ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf));
|
||||
ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_AlphaMask_));
|
||||
|
||||
return pressed;
|
||||
}
|
||||
@@ -6216,7 +6226,8 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags
|
||||
ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2);
|
||||
ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
|
||||
int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]);
|
||||
ColorButton("##preview", cf, (flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz);
|
||||
ImGuiColorEditFlags flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_AlphaMask_;
|
||||
ColorButton("##preview", cf, (flags & flags_to_forward) | ImGuiColorEditFlags_NoTooltip, sz);
|
||||
SameLine();
|
||||
if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags_InputMask_))
|
||||
{
|
||||
@@ -6937,13 +6948,9 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||
if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth))
|
||||
size.x = ImMax(label_size.x, max_x - min_x);
|
||||
|
||||
// Text stays at the submission position, but bounding box may be extended on both sides
|
||||
const ImVec2 text_min = pos;
|
||||
const ImVec2 text_max(min_x + size.x, pos.y + size.y);
|
||||
|
||||
// Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable.
|
||||
// FIXME: Not part of layout so not included in clipper calculation, but ItemSize currently doesn't allow offsetting CursorPos.
|
||||
ImRect bb(min_x, pos.y, text_max.x, text_max.y);
|
||||
ImRect bb(min_x, pos.y, min_x + size.x, pos.y + size.y);
|
||||
if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0)
|
||||
{
|
||||
const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x;
|
||||
@@ -7079,8 +7086,9 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||
PopColumnsBackground();
|
||||
}
|
||||
|
||||
// Text stays at the submission position. Alignment/clipping extents ignore SpanAllColumns.
|
||||
if (is_visible)
|
||||
RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb);
|
||||
RenderTextClipped(pos, ImVec2(window->WorkRect.Max.x, pos.y + size.y), label, NULL, &label_size, style.SelectableTextAlign, &bb);
|
||||
|
||||
// Automatically close popups
|
||||
if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups))
|
||||
@@ -8622,12 +8630,13 @@ bool ImGui::BeginMenuBar()
|
||||
|
||||
IM_ASSERT(!window->DC.MenuBarAppending);
|
||||
BeginGroup(); // Backup position on layer 0 // FIXME: Misleading to use a group for that backup/restore
|
||||
PushID("##menubar");
|
||||
PushID("##MenuBar");
|
||||
|
||||
// We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect.
|
||||
// We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy.
|
||||
const float border_top = ImMax(window->WindowBorderSize * 0.5f - window->TitleBarHeight, 0.0f);
|
||||
ImRect bar_rect = window->MenuBarRect();
|
||||
ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize), IM_ROUND(bar_rect.Min.y + window->WindowBorderSize), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize))), IM_ROUND(bar_rect.Max.y));
|
||||
ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize * 0.5f), IM_ROUND(bar_rect.Min.y + border_top), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize * 0.5f))), IM_ROUND(bar_rect.Max.y));
|
||||
clip_rect.ClipWith(window->OuterRectClipped);
|
||||
PushClipRect(clip_rect.Min, clip_rect.Max, false);
|
||||
|
||||
@@ -8648,6 +8657,10 @@ void ImGui::EndMenuBar()
|
||||
return;
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
||||
IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'"
|
||||
IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar);
|
||||
IM_ASSERT(window->DC.MenuBarAppending);
|
||||
|
||||
// Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings.
|
||||
if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
|
||||
{
|
||||
@@ -8674,9 +8687,6 @@ void ImGui::EndMenuBar()
|
||||
}
|
||||
}
|
||||
|
||||
IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'"
|
||||
IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar);
|
||||
IM_ASSERT(window->DC.MenuBarAppending);
|
||||
PopClipRect();
|
||||
PopID();
|
||||
window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->Pos.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos.
|
||||
@@ -8745,22 +8755,33 @@ bool ImGui::BeginMainMenuBar()
|
||||
float height = GetFrameHeight();
|
||||
bool is_open = BeginViewportSideBar("##MainMenuBar", viewport, ImGuiDir_Up, height, window_flags);
|
||||
g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
|
||||
|
||||
if (is_open)
|
||||
BeginMenuBar();
|
||||
else
|
||||
if (!is_open)
|
||||
{
|
||||
End();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Temporarily disable _NoSavedSettings, in the off-chance that tables or child windows submitted within the menu-bar may want to use settings. (#8356)
|
||||
g.CurrentWindow->Flags &= ~ImGuiWindowFlags_NoSavedSettings;
|
||||
BeginMenuBar();
|
||||
return is_open;
|
||||
}
|
||||
|
||||
void ImGui::EndMainMenuBar()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (!g.CurrentWindow->DC.MenuBarAppending)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(0, "Calling EndMainMenuBar() not from a menu-bar!"); // Not technically testing that it is the main menu bar
|
||||
return;
|
||||
}
|
||||
|
||||
EndMenuBar();
|
||||
g.CurrentWindow->Flags |= ImGuiWindowFlags_NoSavedSettings; // Restore _NoSavedSettings (#8356)
|
||||
|
||||
// When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window
|
||||
// FIXME: With this strategy we won't be able to restore a NULL focus.
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest)
|
||||
if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest && g.ActiveId == 0)
|
||||
FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild);
|
||||
|
||||
End();
|
||||
@@ -9921,7 +9942,7 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f
|
||||
IM_ASSERT_USER_ERROR(tab_bar, "Needs to be called between BeginTabBar() and EndTabBar()!");
|
||||
return false;
|
||||
}
|
||||
IM_ASSERT(!(flags & ImGuiTabItemFlags_Button)); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead!
|
||||
IM_ASSERT((flags & ImGuiTabItemFlags_Button) == 0); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead!
|
||||
|
||||
bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL);
|
||||
if (ret && !(flags & ImGuiTabItemFlags_NoPushId))
|
||||
@@ -9967,6 +9988,23 @@ bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags)
|
||||
return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL);
|
||||
}
|
||||
|
||||
void ImGui::TabItemSpacing(const char* str_id, ImGuiTabItemFlags flags, float width)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
if (window->SkipItems)
|
||||
return;
|
||||
|
||||
ImGuiTabBar* tab_bar = g.CurrentTabBar;
|
||||
if (tab_bar == NULL)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!");
|
||||
return;
|
||||
}
|
||||
SetNextItemWidth(width);
|
||||
TabItemEx(tab_bar, str_id, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder | ImGuiTabItemFlags_Invisible, NULL);
|
||||
}
|
||||
|
||||
bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window)
|
||||
{
|
||||
// Layout whole tab bar if not already done
|
||||
@@ -10112,8 +10150,11 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap);
|
||||
if (g.DragDropActive)
|
||||
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
|
||||
bool hovered, held, pressed;
|
||||
if (flags & ImGuiTabItemFlags_Invisible)
|
||||
hovered = held = pressed = false;
|
||||
else
|
||||
pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
|
||||
if (pressed && !is_tab_button)
|
||||
TabBarQueueFocus(tab_bar, tab);
|
||||
|
||||
@@ -10145,36 +10186,59 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
#endif
|
||||
|
||||
// Render tab shape
|
||||
ImDrawList* display_draw_list = window->DrawList;
|
||||
const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabDimmed));
|
||||
TabItemBackground(display_draw_list, bb, flags, tab_col);
|
||||
if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline) && style.TabBarOverlineSize > 0.0f)
|
||||
const bool is_visible = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) && !(flags & ImGuiTabItemFlags_Invisible);
|
||||
if (is_visible)
|
||||
{
|
||||
float x_offset = IM_TRUNC(0.4f * style.TabRounding);
|
||||
if (x_offset < 2.0f * g.CurrentDpiScale)
|
||||
x_offset = 0.0f;
|
||||
float y_offset = 1.0f * g.CurrentDpiScale;
|
||||
display_draw_list->AddLine(bb.GetTL() + ImVec2(x_offset, y_offset), bb.GetTR() + ImVec2(-x_offset, y_offset), GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline), style.TabBarOverlineSize);
|
||||
}
|
||||
RenderNavCursor(bb, id);
|
||||
ImDrawList* display_draw_list = window->DrawList;
|
||||
const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabDimmed));
|
||||
TabItemBackground(display_draw_list, bb, flags, tab_col);
|
||||
if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline) && style.TabBarOverlineSize > 0.0f)
|
||||
{
|
||||
// Might be moved to TabItemBackground() ?
|
||||
ImVec2 tl = bb.GetTL() + ImVec2(0, 1.0f * g.CurrentDpiScale);
|
||||
ImVec2 tr = bb.GetTR() + ImVec2(0, 1.0f * g.CurrentDpiScale);
|
||||
ImU32 overline_col = GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline);
|
||||
if (style.TabRounding > 0.0f)
|
||||
{
|
||||
float rounding = style.TabRounding;
|
||||
display_draw_list->PathArcToFast(tl + ImVec2(+rounding, +rounding), rounding, 7, 9);
|
||||
display_draw_list->PathArcToFast(tr + ImVec2(-rounding, +rounding), rounding, 9, 11);
|
||||
display_draw_list->PathStroke(overline_col, 0, style.TabBarOverlineSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
display_draw_list->AddLine(tl - ImVec2(0.5f, 0.5f), tr - ImVec2(0.5f, 0.5f), overline_col, style.TabBarOverlineSize);
|
||||
}
|
||||
}
|
||||
RenderNavCursor(bb, id);
|
||||
|
||||
// Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget.
|
||||
const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
|
||||
if (tab_bar->SelectedTabId != tab->ID && hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button)
|
||||
TabBarQueueFocus(tab_bar, tab);
|
||||
// Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget.
|
||||
const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
|
||||
if (tab_bar->SelectedTabId != tab->ID && hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button)
|
||||
TabBarQueueFocus(tab_bar, tab);
|
||||
|
||||
if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)
|
||||
flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;
|
||||
if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)
|
||||
flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;
|
||||
|
||||
// Render tab label, process close button
|
||||
const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0;
|
||||
bool just_closed;
|
||||
bool text_clipped;
|
||||
TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped);
|
||||
if (just_closed && p_open != NULL)
|
||||
{
|
||||
*p_open = false;
|
||||
TabBarCloseTab(tab_bar, tab);
|
||||
// Render tab label, process close button
|
||||
const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0;
|
||||
bool just_closed;
|
||||
bool text_clipped;
|
||||
TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped);
|
||||
if (just_closed && p_open != NULL)
|
||||
{
|
||||
*p_open = false;
|
||||
TabBarCloseTab(tab_bar, tab);
|
||||
}
|
||||
|
||||
// Tooltip
|
||||
// (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok)
|
||||
// (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores)
|
||||
// FIXME: This is a mess.
|
||||
// FIXME: We may want disabled tab to still display the tooltip?
|
||||
if (text_clipped && g.HoveredId == id && !held)
|
||||
if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip))
|
||||
SetItemTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label);
|
||||
}
|
||||
|
||||
// Restore main window position so user can draw there
|
||||
@@ -10182,15 +10246,6 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
PopClipRect();
|
||||
window->DC.CursorPos = backup_main_cursor_pos;
|
||||
|
||||
// Tooltip
|
||||
// (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok)
|
||||
// (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores)
|
||||
// FIXME: This is a mess.
|
||||
// FIXME: We may want disabled tab to still display the tooltip?
|
||||
if (text_clipped && g.HoveredId == id && !held)
|
||||
if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip))
|
||||
SetItemTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label);
|
||||
|
||||
IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected
|
||||
if (is_tab_button)
|
||||
return pressed;
|
||||
|
||||
Binary file not shown.
@@ -1221,43 +1221,32 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</pre>
|
||||
|
||||
<h3>libjpeg - <a href="https://ijg.org/">https://ijg.org/</a></h3>
|
||||
<h3>libjpeg-turbo - <a href="https://github.com/libjpeg-turbo/libjpeg-turbo">https://github.com/libjpeg-turbo/libjpeg-turbo/</a></h3>
|
||||
<pre>
|
||||
The authors make NO WARRANTY or representation, either express or implied,
|
||||
with respect to this software, its quality, accuracy, merchantability, or
|
||||
fitness for a particular purpose. This software is provided "AS IS", and you,
|
||||
its user, assume the entire risk as to its quality and accuracy.
|
||||
Copyright (C)2009-2024 D. R. Commander. All Rights Reserved.
|
||||
Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
|
||||
|
||||
This software is copyright (C) 1991-2024, Thomas G. Lane, Guido Vollbeding.
|
||||
All Rights Reserved except as specified below.
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Permission is hereby granted to use, copy, modify, and distribute this
|
||||
software (or portions thereof) for any purpose, without fee, subject to these
|
||||
conditions:
|
||||
(1) If any part of the source code for this software is distributed, then this
|
||||
README file must be included, with this copyright and no-warranty notice
|
||||
unaltered; and any additions, deletions, or changes to the original files
|
||||
must be clearly indicated in accompanying documentation.
|
||||
(2) If only executable code is distributed, then the accompanying
|
||||
documentation must state that "this software is based in part on the work of
|
||||
the Independent JPEG Group".
|
||||
(3) Permission for use of this software is granted only if the user accepts
|
||||
full responsibility for any undesirable consequences; the authors accept
|
||||
NO LIABILITY for damages of any kind.
|
||||
Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
of conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution. Neither the name of the libjpeg-turbo Project nor the
|
||||
names of its contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
These conditions apply to any software derived from or based on the IJG code,
|
||||
not just to the unmodified library. If you use our work, you ought to
|
||||
acknowledge us.
|
||||
|
||||
Permission is NOT granted for the use of any IJG author's name or company name
|
||||
in advertising or publicity relating to this software or products derived from
|
||||
it. This software may be referred to only as "the Independent JPEG Group's
|
||||
software".
|
||||
|
||||
We specifically permit and encourage the use of this software as the basis of
|
||||
commercial products, provided that all warranty or liability claims are
|
||||
assumed by the product vendor.
|
||||
</pre>
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</pre>
|
||||
|
||||
<h3>LLVM - <a href="https://github.com/llvm/llvm-project">https://github.com/llvm/llvm-project</a></h3>
|
||||
<pre> Apache License
|
||||
@@ -3419,5 +3408,635 @@ https://www.gnu.org/licenses/why-not-lgpl.html.
|
||||
|
||||
</pre>
|
||||
|
||||
<h3>KDDockWidgets - <a href="https://github.com/KDAB/KDDockWidgets">https://github.com/KDAB/KDDockWidgets</a></h3>
|
||||
<pre>
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this license
|
||||
document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for software and
|
||||
other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed to take
|
||||
away your freedom to share and change the works. By contrast, the GNU General
|
||||
Public License is intended to guarantee your freedom to share and change all
|
||||
versions of a program--to make sure it remains free software for all its users.
|
||||
We, the Free Software Foundation, use the GNU General Public License for most
|
||||
of our software; it applies also to any other work released this way by its
|
||||
authors. You can apply it to your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not price. Our
|
||||
General Public Licenses are designed to make sure that you have the freedom
|
||||
to distribute copies of free software (and charge for them if you wish), that
|
||||
you receive source code or can get it if you want it, that you can change
|
||||
the software or use pieces of it in new free programs, and that you know you
|
||||
can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you these rights
|
||||
or asking you to surrender the rights. Therefore, you have certain responsibilities
|
||||
if you distribute copies of the software, or if you modify it: responsibilities
|
||||
to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether gratis or
|
||||
for a fee, you must pass on to the recipients the same freedoms that you received.
|
||||
You must make sure that they, too, receive or can get the source code. And
|
||||
you must show them these terms so they know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps: (1) assert
|
||||
copyright on the software, and (2) offer you this License giving you legal
|
||||
permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains that
|
||||
there is no warranty for this free software. For both users' and authors'
|
||||
sake, the GPL requires that modified versions be marked as changed, so that
|
||||
their problems will not be attributed erroneously to authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run modified
|
||||
versions of the software inside them, although the manufacturer can do so.
|
||||
This is fundamentally incompatible with the aim of protecting users' freedom
|
||||
to change the software. The systematic pattern of such abuse occurs in the
|
||||
area of products for individuals to use, which is precisely where it is most
|
||||
unacceptable. Therefore, we have designed this version of the GPL to prohibit
|
||||
the practice for those products. If such problems arise substantially in other
|
||||
domains, we stand ready to extend this provision to those domains in future
|
||||
versions of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents. States
|
||||
should not allow patents to restrict development and use of software on general-purpose
|
||||
computers, but in those that do, we wish to avoid the special danger that
|
||||
patents applied to a free program could make it effectively proprietary. To
|
||||
prevent this, the GPL assures that patents cannot be used to render the program
|
||||
non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and modification
|
||||
follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of works,
|
||||
such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this License.
|
||||
Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals
|
||||
or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work in
|
||||
a fashion requiring copyright permission, other than the making of an exact
|
||||
copy. The resulting work is called a "modified version" of the earlier work
|
||||
or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based on the
|
||||
Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without permission,
|
||||
would make you directly or secondarily liable for infringement under applicable
|
||||
copyright law, except executing it on a computer or modifying a private copy.
|
||||
Propagation includes copying, distribution (with or without modification),
|
||||
making available to the public, and in some countries other activities as
|
||||
well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other parties
|
||||
to make or receive copies. Mere interaction with a user through a computer
|
||||
network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices" to the
|
||||
extent that it includes a convenient and prominently visible feature that
|
||||
(1) displays an appropriate copyright notice, and (2) tells the user that
|
||||
there is no warranty for the work (except to the extent that warranties are
|
||||
provided), that licensees may convey the work under this License, and how
|
||||
to view a copy of this License. If the interface presents a list of user commands
|
||||
or options, such as a menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work for making
|
||||
modifications to it. "Object code" means any non-source form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official standard
|
||||
defined by a recognized standards body, or, in the case of interfaces specified
|
||||
for a particular programming language, one that is widely used among developers
|
||||
working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other than
|
||||
the work as a whole, that (a) is included in the normal form of packaging
|
||||
a Major Component, but which is not part of that Major Component, and (b)
|
||||
serves only to enable use of the work with that Major Component, or to implement
|
||||
a Standard Interface for which an implementation is available to the public
|
||||
in source code form. A "Major Component", in this context, means a major essential
|
||||
component (kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to produce
|
||||
the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all the source
|
||||
code needed to generate, install, and (for an executable work) run the object
|
||||
code and to modify the work, including scripts to control those activities.
|
||||
However, it does not include the work's System Libraries, or general-purpose
|
||||
tools or generally available free programs which are used unmodified in performing
|
||||
those activities but which are not part of the work. For example, Corresponding
|
||||
Source includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically linked
|
||||
subprograms that the work is specifically designed to require, such as by
|
||||
intimate data communication or control flow between those subprograms and
|
||||
other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users can regenerate
|
||||
automatically from other parts of the Corresponding Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of copyright
|
||||
on the Program, and are irrevocable provided the stated conditions are met.
|
||||
This License explicitly affirms your unlimited permission to run the unmodified
|
||||
Program. The output from running a covered work is covered by this License
|
||||
only if the output, given its content, constitutes a covered work. This License
|
||||
acknowledges your rights of fair use or other equivalent, as provided by copyright
|
||||
law.
|
||||
|
||||
You may make, run and propagate covered works that you do not convey, without
|
||||
conditions so long as your license otherwise remains in force. You may convey
|
||||
covered works to others for the sole purpose of having them make modifications
|
||||
exclusively for you, or provide you with facilities for running those works,
|
||||
provided that you comply with the terms of this License in conveying all material
|
||||
for which you do not control copyright. Those thus making or running the covered
|
||||
works for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of your copyrighted
|
||||
material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under the conditions
|
||||
stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological measure
|
||||
under any applicable law fulfilling obligations under article 11 of the WIPO
|
||||
copyright treaty adopted on 20 December 1996, or similar laws prohibiting
|
||||
or restricting circumvention of such measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid circumvention
|
||||
of technological measures to the extent such circumvention is effected by
|
||||
exercising rights under this License with respect to the covered work, and
|
||||
you disclaim any intention to limit operation or modification of the work
|
||||
as a means of enforcing, against the work's users, your or third parties'
|
||||
legal rights to forbid circumvention of technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you receive
|
||||
it, in any medium, provided that you conspicuously and appropriately publish
|
||||
on each copy an appropriate copyright notice; keep intact all notices stating
|
||||
that this License and any non-permissive terms added in accord with section
|
||||
7 apply to the code; keep intact all notices of the absence of any warranty;
|
||||
and give all recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey, and you
|
||||
may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to produce
|
||||
it from the Program, in the form of source code under the terms of section
|
||||
4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified it, and
|
||||
giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is released under
|
||||
this License and any conditions added under section 7. This requirement modifies
|
||||
the requirement in section 4 to "keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this License to anyone
|
||||
who comes into possession of a copy. This License will therefore apply, along
|
||||
with any applicable section 7 additional terms, to the whole of the work,
|
||||
and all its parts, regardless of how they are packaged. This License gives
|
||||
no permission to license the work in any other way, but it does not invalidate
|
||||
such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display Appropriate
|
||||
Legal Notices; however, if the Program has interactive interfaces that do
|
||||
not display Appropriate Legal Notices, your work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent works,
|
||||
which are not by their nature extensions of the covered work, and which are
|
||||
not combined with it such as to form a larger program, in or on a volume of
|
||||
a storage or distribution medium, is called an "aggregate" if the compilation
|
||||
and its resulting copyright are not used to limit the access or legal rights
|
||||
of the compilation's users beyond what the individual works permit. Inclusion
|
||||
of a covered work in an aggregate does not cause this License to apply to
|
||||
the other parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms of sections
|
||||
4 and 5, provided that you also convey the machine-readable Corresponding
|
||||
Source under the terms of this License, in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product (including
|
||||
a physical distribution medium), accompanied by the Corresponding Source fixed
|
||||
on a durable physical medium customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product (including
|
||||
a physical distribution medium), accompanied by a written offer, valid for
|
||||
at least three years and valid for as long as you offer spare parts or customer
|
||||
support for that product model, to give anyone who possesses the object code
|
||||
either (1) a copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical medium customarily
|
||||
used for software interchange, for a price no more than your reasonable cost
|
||||
of physically performing this conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the written
|
||||
offer to provide the Corresponding Source. This alternative is allowed only
|
||||
occasionally and noncommercially, and only if you received the object code
|
||||
with such an offer, in accord with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated place (gratis
|
||||
or for a charge), and offer equivalent access to the Corresponding Source
|
||||
in the same way through the same place at no further charge. You need not
|
||||
require recipients to copy the Corresponding Source along with the object
|
||||
code. If the place to copy the object code is a network server, the Corresponding
|
||||
Source may be on a different server (operated by you or a third party) that
|
||||
supports equivalent copying facilities, provided you maintain clear directions
|
||||
next to the object code saying where to find the Corresponding Source. Regardless
|
||||
of what server hosts the Corresponding Source, you remain obligated to ensure
|
||||
that it is available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided you inform
|
||||
other peers where the object code and Corresponding Source of the work are
|
||||
being offered to the general public at no charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded from
|
||||
the Corresponding Source as a System Library, need not be included in conveying
|
||||
the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any tangible
|
||||
personal property which is normally used for personal, family, or household
|
||||
purposes, or (2) anything designed or sold for incorporation into a dwelling.
|
||||
In determining whether a product is a consumer product, doubtful cases shall
|
||||
be resolved in favor of coverage. For a particular product received by a particular
|
||||
user, "normally used" refers to a typical or common use of that class of product,
|
||||
regardless of the status of the particular user or of the way in which the
|
||||
particular user actually uses, or expects or is expected to use, the product.
|
||||
A product is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent the
|
||||
only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods, procedures,
|
||||
authorization keys, or other information required to install and execute modified
|
||||
versions of a covered work in that User Product from a modified version of
|
||||
its Corresponding Source. The information must suffice to ensure that the
|
||||
continued functioning of the modified object code is in no case prevented
|
||||
or interfered with solely because modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or specifically
|
||||
for use in, a User Product, and the conveying occurs as part of a transaction
|
||||
in which the right of possession and use of the User Product is transferred
|
||||
to the recipient in perpetuity or for a fixed term (regardless of how the
|
||||
transaction is characterized), the Corresponding Source conveyed under this
|
||||
section must be accompanied by the Installation Information. But this requirement
|
||||
does not apply if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has been installed
|
||||
in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a requirement
|
||||
to continue to provide support service, warranty, or updates for a work that
|
||||
has been modified or installed by the recipient, or for the User Product in
|
||||
which it has been modified or installed. Access to a network may be denied
|
||||
when the modification itself materially and adversely affects the operation
|
||||
of the network or violates the rules and protocols for communication across
|
||||
the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided, in accord
|
||||
with this section must be in a format that is publicly documented (and with
|
||||
an implementation available to the public in source code form), and must require
|
||||
no special password or key for unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this License
|
||||
by making exceptions from one or more of its conditions. Additional permissions
|
||||
that are applicable to the entire Program shall be treated as though they
|
||||
were included in this License, to the extent that they are valid under applicable
|
||||
law. If additional permissions apply only to part of the Program, that part
|
||||
may be used separately under those permissions, but the entire Program remains
|
||||
governed by this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option remove any
|
||||
additional permissions from that copy, or from any part of it. (Additional
|
||||
permissions may be written to require their own removal in certain cases when
|
||||
you modify the work.) You may place additional permissions on material, added
|
||||
by you to a covered work, for which you have or can give appropriate copyright
|
||||
permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you add
|
||||
to a covered work, you may (if authorized by the copyright holders of that
|
||||
material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the terms of
|
||||
sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or author
|
||||
attributions in that material or in the Appropriate Legal Notices displayed
|
||||
by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or requiring
|
||||
that modified versions of such material be marked in reasonable ways as different
|
||||
from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or authors
|
||||
of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some trade names,
|
||||
trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that material by
|
||||
anyone who conveys the material (or modified versions of it) with contractual
|
||||
assumptions of liability to the recipient, for any liability that these contractual
|
||||
assumptions directly impose on those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further restrictions"
|
||||
within the meaning of section 10. If the Program as you received it, or any
|
||||
part of it, contains a notice stating that it is governed by this License
|
||||
along with a term that is a further restriction, you may remove that term.
|
||||
If a license document contains a further restriction but permits relicensing
|
||||
or conveying under this License, you may add to a covered work material governed
|
||||
by the terms of that license document, provided that the further restriction
|
||||
does not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you must place,
|
||||
in the relevant source files, a statement of the additional terms that apply
|
||||
to those files, or a notice indicating where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the form
|
||||
of a separately written license, or stated as exceptions; the above requirements
|
||||
apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly provided
|
||||
under this License. Any attempt otherwise to propagate or modify it is void,
|
||||
and will automatically terminate your rights under this License (including
|
||||
any patent licenses granted under the third paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your license from
|
||||
a particular copyright holder is reinstated (a) provisionally, unless and
|
||||
until the copyright holder explicitly and finally terminates your license,
|
||||
and (b) permanently, if the copyright holder fails to notify you of the violation
|
||||
by some reasonable means prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is reinstated permanently
|
||||
if the copyright holder notifies you of the violation by some reasonable means,
|
||||
this is the first time you have received notice of violation of this License
|
||||
(for any work) from that copyright holder, and you cure the violation prior
|
||||
to 30 days after your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the licenses
|
||||
of parties who have received copies or rights from you under this License.
|
||||
If your rights have been terminated and not permanently reinstated, you do
|
||||
not qualify to receive new licenses for the same material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or run a copy
|
||||
of the Program. Ancillary propagation of a covered work occurring solely as
|
||||
a consequence of using peer-to-peer transmission to receive a copy likewise
|
||||
does not require acceptance. However, nothing other than this License grants
|
||||
you permission to propagate or modify any covered work. These actions infringe
|
||||
copyright if you do not accept this License. Therefore, by modifying or propagating
|
||||
a covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically receives
|
||||
a license from the original licensors, to run, modify and propagate that work,
|
||||
subject to this License. You are not responsible for enforcing compliance
|
||||
by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an organization,
|
||||
or substantially all assets of one, or subdividing an organization, or merging
|
||||
organizations. If propagation of a covered work results from an entity transaction,
|
||||
each party to that transaction who receives a copy of the work also receives
|
||||
whatever licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the Corresponding
|
||||
Source of the work from the predecessor in interest, if the predecessor has
|
||||
it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the rights
|
||||
granted or affirmed under this License. For example, you may not impose a
|
||||
license fee, royalty, or other charge for exercise of rights granted under
|
||||
this License, and you may not initiate litigation (including a cross-claim
|
||||
or counterclaim in a lawsuit) alleging that any patent claim is infringed
|
||||
by making, using, selling, offering for sale, or importing the Program or
|
||||
any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this License
|
||||
of the Program or a work on which the Program is based. The work thus licensed
|
||||
is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims owned or controlled
|
||||
by the contributor, whether already acquired or hereafter acquired, that would
|
||||
be infringed by some manner, permitted by this License, of making, using,
|
||||
or selling its contributor version, but do not include claims that would be
|
||||
infringed only as a consequence of further modification of the contributor
|
||||
version. For purposes of this definition, "control" includes the right to
|
||||
grant patent sublicenses in a manner consistent with the requirements of this
|
||||
License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free patent
|
||||
license under the contributor's essential patent claims, to make, use, sell,
|
||||
offer for sale, import and otherwise run, modify and propagate the contents
|
||||
of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express agreement
|
||||
or commitment, however denominated, not to enforce a patent (such as an express
|
||||
permission to practice a patent or covenant not to sue for patent infringement).
|
||||
To "grant" such a patent license to a party means to make such an agreement
|
||||
or commitment not to enforce a patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license, and the
|
||||
Corresponding Source of the work is not available for anyone to copy, free
|
||||
of charge and under the terms of this License, through a publicly available
|
||||
network server or other readily accessible means, then you must either (1)
|
||||
cause the Corresponding Source to be so available, or (2) arrange to deprive
|
||||
yourself of the benefit of the patent license for this particular work, or
|
||||
(3) arrange, in a manner consistent with the requirements of this License,
|
||||
to extend the patent license to downstream recipients. "Knowingly relying"
|
||||
means you have actual knowledge that, but for the patent license, your conveying
|
||||
the covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that country
|
||||
that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or arrangement,
|
||||
you convey, or propagate by procuring conveyance of, a covered work, and grant
|
||||
a patent license to some of the parties receiving the covered work authorizing
|
||||
them to use, propagate, modify or convey a specific copy of the covered work,
|
||||
then the patent license you grant is automatically extended to all recipients
|
||||
of the covered work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within the scope
|
||||
of its coverage, prohibits the exercise of, or is conditioned on the non-exercise
|
||||
of one or more of the rights that are specifically granted under this License.
|
||||
You may not convey a covered work if you are a party to an arrangement with
|
||||
a third party that is in the business of distributing software, under which
|
||||
you make payment to the third party based on the extent of your activity of
|
||||
conveying the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory patent
|
||||
license (a) in connection with copies of the covered work conveyed by you
|
||||
(or copies made from those copies), or (b) primarily for and in connection
|
||||
with specific products or compilations that contain the covered work, unless
|
||||
you entered into that arrangement, or that patent license was granted, prior
|
||||
to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting any implied
|
||||
license or other defenses to infringement that may otherwise be available
|
||||
to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or otherwise)
|
||||
that contradict the conditions of this License, they do not excuse you from
|
||||
the conditions of this License. If you cannot convey a covered work so as
|
||||
to satisfy simultaneously your obligations under this License and any other
|
||||
pertinent obligations, then as a consequence you may not convey it at all.
|
||||
For example, if you agree to terms that obligate you to collect a royalty
|
||||
for further conveying from those to whom you convey the Program, the only
|
||||
way you could satisfy both those terms and this License would be to refrain
|
||||
entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have permission to
|
||||
link or combine any covered work with a work licensed under version 3 of the
|
||||
GNU Affero General Public License into a single combined work, and to convey
|
||||
the resulting work. The terms of this License will continue to apply to the
|
||||
part which is the covered work, but the special requirements of the GNU Affero
|
||||
General Public License, section 13, concerning interaction through a network
|
||||
will apply to the combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of the
|
||||
GNU General Public License from time to time. Such new versions will be similar
|
||||
in spirit to the present version, but may differ in detail to address new
|
||||
problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program specifies
|
||||
that a certain numbered version of the GNU General Public License "or any
|
||||
later version" applies to it, you have the option of following the terms and
|
||||
conditions either of that numbered version or of any later version published
|
||||
by the Free Software Foundation. If the Program does not specify a version
|
||||
number of the GNU General Public License, you may choose any version ever
|
||||
published by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future versions of
|
||||
the GNU General Public License can be used, that proxy's public statement
|
||||
of acceptance of a version permanently authorizes you to choose that version
|
||||
for the Program.
|
||||
|
||||
Later license versions may give you additional or different permissions. However,
|
||||
no additional obligations are imposed on any author or copyright holder as
|
||||
a result of your choosing to follow a later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
|
||||
LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM
|
||||
PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
|
||||
CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
|
||||
ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM
|
||||
AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
|
||||
INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO
|
||||
USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
|
||||
INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
|
||||
PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
|
||||
PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided above cannot
|
||||
be given local legal effect according to their terms, reviewing courts shall
|
||||
apply local law that most closely approximates an absolute waiver of all civil
|
||||
liability in connection with the Program, unless a warranty or assumption
|
||||
of liability accompanies a copy of the Program in return for a fee. END OF
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest possible
|
||||
use to the public, the best way to achieve this is to make it free software
|
||||
which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest to attach
|
||||
them to the start of each source file to most effectively state the exclusion
|
||||
of warranty; and each file should have at least the "copyright" line and a
|
||||
pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short notice like
|
||||
this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
|
||||
This is free software, and you are welcome to redistribute it under certain
|
||||
conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands might
|
||||
be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary. For
|
||||
more information on this, and how to apply and follow the GNU GPL, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General Public
|
||||
License instead of this License. But first, please read <https://www.gnu.org/
|
||||
licenses /why-not-lgpl.html>.
|
||||
|
||||
</pre>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -211,7 +211,7 @@
|
||||
03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows,
|
||||
03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows,
|
||||
03000000b40400001024000000000000,Flydigi Apex,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,misc1:b15,paddle1:b11,paddle2:b10,paddle3:b13,paddle4:b12,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows,
|
||||
03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows,
|
||||
03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows,
|
||||
03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows,
|
||||
@@ -325,7 +325,7 @@
|
||||
030000000d0f0000c100000000000000,Horipad Nintendo Switch 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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Windows,
|
||||
030000000d0f00009601000000000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b15,paddle2:b5,paddle3:b19,paddle4:b18,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
030000000d0f00009601000000000000,Horipad Steam,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,misc2:b2,paddle1:b5,paddle2:b15,paddle3:b18,paddle4:b19,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows,
|
||||
03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows,
|
||||
@@ -387,7 +387,7 @@
|
||||
03000000380700006652000000000000,Mad Catz CTRLR,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:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000380700005032000000000000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,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:Windows,
|
||||
03000000380700008031000000000000,Mad Catz FightStick Alpha PS3 ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000380700008031000000000000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000380700008433000000000000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,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:Windows,
|
||||
@@ -446,7 +446,6 @@
|
||||
03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
|
||||
03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows,
|
||||
03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows,
|
||||
030000006f0e00001311000000000000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Windows,
|
||||
030000006b140000010c000000000000,Nacon GC 400ES,a:b0,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:b2,y:b3,platform:Windows,
|
||||
030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
0300000085320000170d000000000000,Nacon Revolution 5 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:Windows,
|
||||
@@ -481,6 +480,7 @@
|
||||
030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
|
||||
0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,
|
||||
03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
@@ -637,8 +637,9 @@
|
||||
030000000d0f0000ad00000000000000,RX Gamepad,a:b0,b:b4,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b6,start:b9,x:b2,y:b1,platform:Windows,
|
||||
030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000006f0e00001311000000000000,Saffun Controller,a:b2,b:b3,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:b1,y:b0,platform:Windows,
|
||||
03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000a306000023f6000000000000,Saitek Cyborg V.1 Game,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:a4,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000a306000023f6000000000000,Saitek Cyborg,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:a4,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000300f00001201000000000000,Saitek Dual Analog,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:Windows,
|
||||
03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows,
|
||||
03000000a30600000cff000000000000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows,
|
||||
@@ -665,7 +666,7 @@
|
||||
03000000952e00002577000000000000,Scuf 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,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,
|
||||
03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a2,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows,
|
||||
03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
@@ -967,6 +968,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
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,
|
||||
03000000380700008483000000010000,Mad Catz PS4 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: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,
|
||||
0300000049190000020400001b010000,Manba One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000790000000600000007010000,Marvo GT-004,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:Mac OS X,
|
||||
030000008f0e00001330000011010000,Mayflash Controller Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,platform:Mac OS X,
|
||||
03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,
|
||||
@@ -998,7 +1000,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,
|
||||
030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000790000001c18000000010000,PB Tails Choc,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000d620000011a7000000020000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
@@ -1051,7 +1052,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
|
||||
030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,
|
||||
03000000bc2000000155000000010000,SNK NEOGEO Arcade Stick Pro,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b2,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b0,y:b3,platform:Mac OS X,
|
||||
030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,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,
|
||||
030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,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,
|
||||
03000000666600006706000088020000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X,
|
||||
@@ -1071,6 +1071,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000e40a00000307000001000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,
|
||||
03000000e40a00000207000001000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,
|
||||
03000000790000001c18000000010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X,
|
||||
@@ -1245,6 +1246,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
05000000bc2000000055000001000000,Betop AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000120c0000300e000011010000,Brook Audio Fighting Board PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000120c0000310e000011010000,Brook Audio Fighting Board PS4,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:Linux,
|
||||
03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1266,6 +1269,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch 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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch 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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03005036852100000201000010010000,Final Fantasy XIV Online 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,
|
||||
05000000b40400001224000001010000,Flydigi APEX 4,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b20,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
@@ -1328,6 +1332,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,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,
|
||||
030000000d0f0000c100000011010000,Horipad Nintendo Switch 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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000000d0f00006700000001010000,Horipad One,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,
|
||||
030000000d0f0000ab01000011010000,Horipad Steam,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,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000000d0f00009601000091000000,Horipad Steam,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,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000000d0f0000f600000001000000,Horipad Switch Pro Controller,a:b0,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:b2,y:b3,platform:Linux,
|
||||
03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
|
||||
05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Linux,
|
||||
@@ -1378,6 +1384,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,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:Linux,
|
||||
03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000380700008031000011010000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000380700008081000011010000,Mad Catz FightStick Alpha PS4,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,
|
||||
03000000380700008034000011010000,Mad Catz Fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
03000000380700008433000011010000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1439,7 +1447,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
|
||||
030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,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,
|
||||
03000000f70600000100000000010000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Linux,
|
||||
030000006f0e00001311000011010000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Linux,
|
||||
030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006b140000010c000010010000,Nacon GC 400ES,a:b0,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:b2,y:b3,platform:Linux,
|
||||
03000000853200000706000012010000,Nacon GC-100,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,
|
||||
@@ -1495,12 +1502,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00002f01000011010000,PDP Wired 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,
|
||||
03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000f102000000000000,PDP Xbox Atomic,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,
|
||||
030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,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,
|
||||
030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000c62400000053000000010000,PowerA,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,
|
||||
03000000c62400003a54000001010000,PowerA 1428124-01,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,
|
||||
03000000d62000000540000001010000,PowerA Advantage Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000d620000011a7000011010000,PowerA Core 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,
|
||||
03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1516,8 +1525,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
|
||||
03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,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,
|
||||
03000000d62000000520000050010000,PowerA Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000d62000000b20000001010000,PowerA Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000d62000000540000001010000,PowerA Advantage Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
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,
|
||||
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,
|
||||
@@ -1591,6 +1600,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
050000003215000000090000163a0000,Razer Serval,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:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
0300000032150000030a000001010000,Razer Wildcat,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,
|
||||
03000000321500000b10000011010000,Razer Wolverine PS5 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,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
0300000032150000140a000001010000,Razer Wolverine Ultimate Xbox,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,
|
||||
030000000d0f0000c100000010010000,Retro Bit Legacy16,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b12,leftshoulder:b4,lefttrigger:b6,misc1:b13,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000000d0f0000c100000072056800,Retro Bit Legacy16,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:+a4,misc1:b11,rightshoulder:b10,righttrigger:+a5,start:b6,x:b3,y:b2,platform:Linux,
|
||||
03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1607,6 +1617,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006f0e00001e01000011010000,Rock Candy 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,
|
||||
03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,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,
|
||||
030000006f0e00001311000011010000,Saffun Controller,a:b2,b:b3,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:b1,y:b0,platform:Linux,
|
||||
03000000a306000023f6000011010000,Saitek Cyborg PlayStation 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:a4,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux,
|
||||
03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux,
|
||||
@@ -1627,7 +1638,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
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,
|
||||
030000001f08000001e4000010010000,SFC Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,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,
|
||||
03000000632500007505000010010000,Shanwan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
@@ -1664,6 +1674,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux,
|
||||
030000001f08000001e4000010010000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
|
||||
0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
|
||||
030000008f0e00000d31000010010000,SZMY Power 3 Turbo,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,
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 91 KiB |
@@ -799,7 +799,8 @@ void ps_fbmask(inout float4 C, float2 pos_xy)
|
||||
{
|
||||
if (PS_FBMASK)
|
||||
{
|
||||
float4 RT = trunc(RtTexture.Load(int3(pos_xy, 0)) * 255.0f + 0.1f);
|
||||
float multi = PS_HDR ? 65535.0f : 255.0f;
|
||||
float4 RT = trunc(RtTexture.Load(int3(pos_xy, 0)) * multi + 0.1f);
|
||||
C = (float4)(((uint4)C & ~FbMask) | ((uint4)RT & FbMask));
|
||||
}
|
||||
}
|
||||
@@ -895,7 +896,8 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
|
||||
}
|
||||
|
||||
float Ad = PS_RTA_CORRECTION ? trunc(RT.a * 128.0f + 0.1f) / 128.0f : trunc(RT.a * 255.0f + 0.1f) / 128.0f;
|
||||
float3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
|
||||
float color_multi = PS_HDR ? 65535.0f : 255.0f;
|
||||
float3 Cd = trunc(RT.rgb * color_multi + 0.1f);
|
||||
float3 Cs = Color.rgb;
|
||||
|
||||
float3 A = (PS_BLEND_A == 0) ? Cs : ((PS_BLEND_A == 1) ? Cd : (float3)0.0f);
|
||||
|
||||
@@ -111,7 +111,7 @@ layout(binding = 3) uniform sampler2D img_prim_min;
|
||||
//layout(pixel_center_integer) in vec4 gl_FragCoord;
|
||||
#endif
|
||||
|
||||
vec4 fetch_rt()
|
||||
vec4 sample_from_rt()
|
||||
{
|
||||
#if !NEEDS_RT
|
||||
return vec4(0.0);
|
||||
@@ -127,7 +127,7 @@ vec4 fetch_rt()
|
||||
vec4 sample_c(vec2 uv)
|
||||
{
|
||||
#if PS_TEX_IS_FB == 1
|
||||
return fetch_rt();
|
||||
return sample_from_rt();
|
||||
#elif PS_REGION_RECT
|
||||
return texelFetch(TextureSampler, ivec2(uv), 0);
|
||||
#else
|
||||
@@ -312,7 +312,7 @@ int fetch_raw_depth()
|
||||
float multiplier = exp2(32.0f);
|
||||
|
||||
#if PS_TEX_IS_FB == 1
|
||||
return int(fetch_rt().r * multiplier);
|
||||
return int(sample_from_rt().r * multiplier);
|
||||
#else
|
||||
return int(texelFetch(TextureSampler, ivec2(gl_FragCoord.xy), 0).r * multiplier);
|
||||
#endif
|
||||
@@ -321,7 +321,7 @@ int fetch_raw_depth()
|
||||
vec4 fetch_raw_color()
|
||||
{
|
||||
#if PS_TEX_IS_FB == 1
|
||||
return fetch_rt();
|
||||
return sample_from_rt();
|
||||
#else
|
||||
return texelFetch(TextureSampler, ivec2(gl_FragCoord.xy), 0);
|
||||
#endif
|
||||
@@ -697,8 +697,6 @@ vec4 ps_color()
|
||||
|
||||
vec4 C = tfx(T, PSin.c);
|
||||
|
||||
atst(C);
|
||||
|
||||
fog(C, PSin.t_float.z);
|
||||
|
||||
return C;
|
||||
@@ -708,7 +706,11 @@ void ps_fbmask(inout vec4 C)
|
||||
{
|
||||
// FIXME do I need special case for 16 bits
|
||||
#if PS_FBMASK
|
||||
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
|
||||
#if PS_HDR == 1
|
||||
vec4 RT = trunc(sample_from_rt() * 65535.0f);
|
||||
#else
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
#endif
|
||||
C = vec4((uvec4(C) & ~FbMask) | (uvec4(RT) & FbMask));
|
||||
#endif
|
||||
}
|
||||
@@ -795,7 +797,7 @@ float As = As_rgba.a;
|
||||
#endif
|
||||
|
||||
#if SW_BLEND_NEEDS_RT
|
||||
vec4 RT = fetch_rt();
|
||||
vec4 RT = sample_from_rt();
|
||||
#else
|
||||
// Not used, but we define it to make the selection below simpler.
|
||||
vec4 RT = vec4(0.0f);
|
||||
@@ -823,7 +825,11 @@ float As = As_rgba.a;
|
||||
#endif
|
||||
|
||||
// Let the compiler do its jobs !
|
||||
vec3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
|
||||
#if PS_HDR == 1
|
||||
vec3 Cd = trunc(RT.rgb * 65535.0f);
|
||||
#else
|
||||
vec3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
|
||||
#endif
|
||||
vec3 Cs = Color.rgb;
|
||||
|
||||
#if PS_BLEND_A == 0
|
||||
@@ -966,9 +972,9 @@ void ps_main()
|
||||
|
||||
#if PS_WRITE_RG == 1
|
||||
// Pseudo 16 bits access.
|
||||
float rt_a = fetch_rt().g;
|
||||
float rt_a = sample_from_rt().g;
|
||||
#else
|
||||
float rt_a = fetch_rt().a;
|
||||
float rt_a = sample_from_rt().a;
|
||||
#endif
|
||||
|
||||
#if (PS_DATE & 3) == 1
|
||||
@@ -1020,9 +1026,9 @@ void ps_main()
|
||||
|
||||
#if SW_AD_TO_HW
|
||||
#if PS_RTA_CORRECTION
|
||||
vec4 RT = trunc(fetch_rt() * 128.0f + 0.1f);
|
||||
vec4 RT = trunc(sample_from_rt() * 128.0f + 0.1f);
|
||||
#else
|
||||
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
#endif
|
||||
|
||||
vec4 alpha_blend = vec4(RT.a / 128.0f);
|
||||
|
||||
@@ -954,7 +954,7 @@ vec4 ps_color()
|
||||
T.a = float(denorm_c_before.a & 0x80u);
|
||||
#else
|
||||
T.r = float((denorm_c_before.r << 3) & 0xF8u);
|
||||
T.g = float(((denorm_c_before.r >> 2) & 0x38) | ((denorm_c_before.g << 6) & 0xC0u));
|
||||
T.g = float(((denorm_c_before.r >> 2) & 0x38u) | ((denorm_c_before.g << 6) & 0xC0u));
|
||||
T.b = float((denorm_c_before.g << 1) & 0xF8u);
|
||||
T.a = float(denorm_c_before.g & 0x80u);
|
||||
#endif
|
||||
@@ -972,7 +972,12 @@ vec4 ps_color()
|
||||
void ps_fbmask(inout vec4 C)
|
||||
{
|
||||
#if PS_FBMASK
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
|
||||
#if PS_HDR == 1
|
||||
vec4 RT = trunc(sample_from_rt() * 65535.0f);
|
||||
#else
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
#endif
|
||||
C = vec4((uvec4(C) & ~FbMask) | (uvec4(RT) & FbMask));
|
||||
#endif
|
||||
}
|
||||
@@ -1090,7 +1095,11 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba)
|
||||
#endif
|
||||
|
||||
// Let the compiler do its jobs !
|
||||
#if PS_HDR == 1
|
||||
vec3 Cd = trunc(RT.rgb * 65535.0f);
|
||||
#else
|
||||
vec3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
|
||||
#endif
|
||||
vec3 Cs = Color.rgb;
|
||||
|
||||
#if PS_BLEND_A == 0
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
lbsubmit.wav: https://freesound.org/people/Eponn/sounds/636656/
|
||||
unlock.wav and message.wav are from https://github.com/RetroAchievements/RAInterface
|
||||
message.wav is from https://github.com/RetroAchievements/RAInterface
|
||||
unlock.wav is from https://freesound.org/people/rhodesmas/sounds/320655/
|
||||
|
||||
Binary file not shown.
@@ -146,15 +146,11 @@ if(MSVC AND NOT USE_CLANG_CL)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
# Disable RTTI
|
||||
string(REPLACE "/GR" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
|
||||
# Disable Exceptions
|
||||
string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
else()
|
||||
add_compile_options(-pipe -fvisibility=hidden -pthread)
|
||||
add_compile_options(
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>"
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -17,7 +17,7 @@ find_package(ZLIB REQUIRED) # v1.3, but Mac uses the SDK version.
|
||||
find_package(Zstd 1.5.5 REQUIRED)
|
||||
find_package(LZ4 REQUIRED)
|
||||
find_package(WebP REQUIRED) # v1.3.2, spews an error on Linux because no pkg-config.
|
||||
find_package(SDL2 2.30.4 REQUIRED)
|
||||
find_package(SDL3 3.2.6 REQUIRED)
|
||||
find_package(Freetype 2.11.1 REQUIRED)
|
||||
|
||||
if(USE_VULKAN)
|
||||
@@ -105,7 +105,7 @@ disable_compiler_warnings_for_target(cubeb)
|
||||
disable_compiler_warnings_for_target(speex)
|
||||
|
||||
# Find the Qt components that we need.
|
||||
find_package(Qt6 6.7.2 COMPONENTS CoreTools Core GuiTools Gui WidgetsTools Widgets LinguistTools REQUIRED)
|
||||
find_package(Qt6 6.7.3 COMPONENTS CoreTools Core GuiTools Gui WidgetsTools Widgets LinguistTools REQUIRED)
|
||||
|
||||
if(WIN32)
|
||||
add_subdirectory(3rdparty/rainterface EXCLUDE_FROM_ALL)
|
||||
@@ -117,6 +117,15 @@ add_subdirectory(3rdparty/demangler EXCLUDE_FROM_ALL)
|
||||
# Symbol table parser.
|
||||
add_subdirectory(3rdparty/ccc EXCLUDE_FROM_ALL)
|
||||
|
||||
# The docking system for the debugger.
|
||||
find_package(KDDockWidgets-qt6 REQUIRED)
|
||||
# Add an extra include path to work around a broken include directive.
|
||||
# TODO: Remove this the next time we update KDDockWidgets.
|
||||
get_target_property(KDDOCKWIDGETS_INCLUDE_DIRECTORY KDAB::kddockwidgets INTERFACE_INCLUDE_DIRECTORIES)
|
||||
target_include_directories(KDAB::kddockwidgets INTERFACE
|
||||
${KDDOCKWIDGETS_INCLUDE_DIRECTORY}/kddockwidgets
|
||||
)
|
||||
|
||||
# Architecture-specific.
|
||||
if(_M_X86)
|
||||
add_subdirectory(3rdparty/zydis EXCLUDE_FROM_ALL)
|
||||
|
||||
@@ -168,6 +168,7 @@ else()
|
||||
${DBUS_LINK_LIBRARIES}
|
||||
X11::X11
|
||||
X11::Xrandr
|
||||
X11::Xi
|
||||
)
|
||||
if(USE_BACKTRACE)
|
||||
target_compile_definitions(common PRIVATE "HAS_LIBBACKTRACE=1")
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <mach/task.h>
|
||||
#include <mach/vm_map.h>
|
||||
#include <mutex>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
|
||||
// Darwin (OSX) is a bit different from Linux when requesting properties of
|
||||
@@ -127,6 +128,69 @@ bool Common::InhibitScreensaver(bool inhibit)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Common::SetMousePosition(int x, int y)
|
||||
{
|
||||
// Little bit ugly but;
|
||||
// Creating mouse move events and posting them wasn't very reliable.
|
||||
// Calling CGWarpMouseCursorPosition without CGAssociateMouseAndMouseCursorPosition(false)
|
||||
// ends up with the cursor feeling "sticky".
|
||||
CGAssociateMouseAndMouseCursorPosition(false);
|
||||
CGWarpMouseCursorPosition(CGPointMake(x, y));
|
||||
CGAssociateMouseAndMouseCursorPosition(true); // The default state
|
||||
return;
|
||||
}
|
||||
|
||||
CFMachPortRef mouseEventTap = nullptr;
|
||||
CFRunLoopSourceRef mouseRunLoopSource = nullptr;
|
||||
|
||||
static std::function<void(int, int)> fnMouseMoveCb;
|
||||
CGEventRef mouseMoveCallback(CGEventTapProxy, CGEventType type, CGEventRef event, void* arg)
|
||||
{
|
||||
if (type == kCGEventMouseMoved)
|
||||
{
|
||||
const CGPoint location = CGEventGetLocation(event);
|
||||
fnMouseMoveCb(location.x, location.y);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
bool Common::AttachMousePositionCb(std::function<void(int, int)> cb)
|
||||
{
|
||||
if (!AXIsProcessTrusted())
|
||||
{
|
||||
Console.Warning("Process isn't trusted with accessibility permissions. Mouse tracking will not work!");
|
||||
}
|
||||
|
||||
fnMouseMoveCb = cb;
|
||||
mouseEventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault,
|
||||
CGEventMaskBit(kCGEventMouseMoved), mouseMoveCallback, nullptr);
|
||||
if (!mouseEventTap)
|
||||
{
|
||||
Console.Warning("Unable to create mouse moved event tap. Mouse tracking will not work!");
|
||||
return false;
|
||||
}
|
||||
|
||||
mouseRunLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, mouseEventTap, 0);
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), mouseRunLoopSource, kCFRunLoopCommonModes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Common::DetachMousePositionCb()
|
||||
{
|
||||
if (mouseRunLoopSource)
|
||||
{
|
||||
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mouseRunLoopSource, kCFRunLoopCommonModes);
|
||||
CFRelease(mouseRunLoopSource);
|
||||
}
|
||||
if (mouseEventTap)
|
||||
{
|
||||
CFRelease(mouseEventTap);
|
||||
}
|
||||
mouseRunLoopSource = nullptr;
|
||||
mouseEventTap = nullptr;
|
||||
}
|
||||
|
||||
void Threading::Sleep(int ms)
|
||||
{
|
||||
usleep(1000 * ms);
|
||||
|
||||
@@ -288,8 +288,14 @@ std::string Path::RealPath(const std::string_view path)
|
||||
{
|
||||
// Resolve non-absolute paths first.
|
||||
std::vector<std::string_view> components;
|
||||
// We need to keep the full combined path in scope
|
||||
// as SplitNativePath() returns string_views to it.
|
||||
std::string buf;
|
||||
if (!IsAbsolute(path))
|
||||
components = Path::SplitNativePath(Path::Combine(FileSystem::GetWorkingDirectory(), path));
|
||||
{
|
||||
buf = Path::Combine(FileSystem::GetWorkingDirectory(), path);
|
||||
components = Path::SplitNativePath(buf);
|
||||
}
|
||||
else
|
||||
components = Path::SplitNativePath(path);
|
||||
|
||||
@@ -968,7 +974,7 @@ std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode, Error*
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const std::wstring wfilename = GetWin32Path(filename);
|
||||
const std::wstring wmode = GetWin32Path(mode);
|
||||
const std::wstring wmode = StringUtil::UTF8StringToWideString(mode);
|
||||
if (!wfilename.empty() && !wmode.empty())
|
||||
{
|
||||
std::FILE* fp;
|
||||
@@ -1060,7 +1066,7 @@ std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, F
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const std::wstring wfilename = GetWin32Path(filename);
|
||||
const std::wstring wmode = GetWin32Path(mode);
|
||||
const std::wstring wmode = StringUtil::UTF8StringToWideString(mode);
|
||||
if (wfilename.empty() || wmode.empty())
|
||||
return nullptr;
|
||||
|
||||
@@ -1354,8 +1360,11 @@ static u32 TranslateWin32Attributes(u32 Win32Attributes)
|
||||
}
|
||||
|
||||
static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path, const char* path, const char* pattern,
|
||||
u32 flags, FileSystem::FindResultsArray* results, std::vector<std::string>& visited)
|
||||
u32 flags, FileSystem::FindResultsArray* results, std::vector<std::string>& visited, ProgressCallback* cancel)
|
||||
{
|
||||
if (cancel && cancel->IsCancelled())
|
||||
return 0;
|
||||
|
||||
std::string search_dir;
|
||||
if (path)
|
||||
{
|
||||
@@ -1427,11 +1436,11 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
|
||||
if (parent_path)
|
||||
{
|
||||
const std::string recurse_dir = fmt::format("{}\\{}", parent_path, path);
|
||||
nFiles += RecursiveFindFiles(origin_path, recurse_dir.c_str(), utf8_filename.c_str(), pattern, flags, results, visited);
|
||||
nFiles += RecursiveFindFiles(origin_path, recurse_dir.c_str(), utf8_filename.c_str(), pattern, flags, results, visited, cancel);
|
||||
}
|
||||
else
|
||||
{
|
||||
nFiles += RecursiveFindFiles(origin_path, path, utf8_filename.c_str(), pattern, flags, results, visited);
|
||||
nFiles += RecursiveFindFiles(origin_path, path, utf8_filename.c_str(), pattern, flags, results, visited, cancel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1494,7 +1503,7 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
|
||||
return nFiles;
|
||||
}
|
||||
|
||||
bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results)
|
||||
bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results, ProgressCallback* cancel)
|
||||
{
|
||||
// has a path
|
||||
if (path[0] == '\0')
|
||||
@@ -1514,7 +1523,7 @@ bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, Fin
|
||||
}
|
||||
|
||||
// enter the recursive function
|
||||
if (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) == 0)
|
||||
if (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited, cancel) == 0)
|
||||
return false;
|
||||
|
||||
if (flags & FILESYSTEM_FIND_SORT_BY_NAME)
|
||||
@@ -2046,8 +2055,11 @@ bool FileSystem::DeleteSymbolicLink(const char* path, Error* error)
|
||||
static_assert(sizeof(off_t) == sizeof(s64));
|
||||
|
||||
static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, const char* Path, const char* Pattern,
|
||||
u32 Flags, FileSystem::FindResultsArray* pResults, std::vector<std::string>& visited)
|
||||
u32 Flags, FileSystem::FindResultsArray* pResults, std::vector<std::string>& visited, ProgressCallback* cancel)
|
||||
{
|
||||
if (cancel && cancel->IsCancelled())
|
||||
return 0;
|
||||
|
||||
std::string tempStr;
|
||||
if (Path)
|
||||
{
|
||||
@@ -2118,11 +2130,11 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
|
||||
if (ParentPath)
|
||||
{
|
||||
const std::string recursive_dir = fmt::format("{}/{}", ParentPath, Path);
|
||||
nFiles += RecursiveFindFiles(OriginPath, recursive_dir.c_str(), pDirEnt->d_name, Pattern, Flags, pResults, visited);
|
||||
nFiles += RecursiveFindFiles(OriginPath, recursive_dir.c_str(), pDirEnt->d_name, Pattern, Flags, pResults, visited, cancel);
|
||||
}
|
||||
else
|
||||
{
|
||||
nFiles += RecursiveFindFiles(OriginPath, Path, pDirEnt->d_name, Pattern, Flags, pResults, visited);
|
||||
nFiles += RecursiveFindFiles(OriginPath, Path, pDirEnt->d_name, Pattern, Flags, pResults, visited, cancel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2177,7 +2189,7 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
|
||||
return nFiles;
|
||||
}
|
||||
|
||||
bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results)
|
||||
bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results, ProgressCallback* cancel)
|
||||
{
|
||||
// has a path
|
||||
if (path[0] == '\0')
|
||||
@@ -2197,7 +2209,7 @@ bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, Fin
|
||||
}
|
||||
|
||||
// enter the recursive function
|
||||
if (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) == 0)
|
||||
if (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited, cancel) == 0)
|
||||
return false;
|
||||
|
||||
if (flags & FILESYSTEM_FIND_SORT_BY_NAME)
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace FileSystem
|
||||
std::vector<std::string> GetRootDirectoryList();
|
||||
|
||||
/// Search for files
|
||||
bool FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results);
|
||||
bool FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results, ProgressCallback* cancel = nullptr);
|
||||
|
||||
/// Stat file
|
||||
bool StatFile(const char* path, struct stat* st);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "common/Pcsx2Defs.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -198,4 +199,8 @@ namespace Common
|
||||
/// Abstracts platform-specific code for asynchronously playing a sound.
|
||||
/// On Windows, this will use PlaySound(). On Linux, it will shell out to aplay. On MacOS, it uses NSSound.
|
||||
bool PlaySoundAsync(const char* path);
|
||||
|
||||
void SetMousePosition(int x, int y);
|
||||
bool AttachMousePositionCb(std::function<void(int,int)> cb);
|
||||
void DetachMousePositionCb();
|
||||
} // namespace Common
|
||||
|
||||
@@ -13,17 +13,20 @@
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <optional>
|
||||
#include <dbus/dbus.h>
|
||||
#include <spawn.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <dbus/dbus.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <ctype.h>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
|
||||
// Returns 0 on failure (not supported by the operating system).
|
||||
u64 GetPhysicalMemory()
|
||||
@@ -177,6 +180,111 @@ bool Common::InhibitScreensaver(bool inhibit)
|
||||
return SetScreensaverInhibitDBus(inhibit, "PCSX2", "PCSX2 VM is running.");
|
||||
}
|
||||
|
||||
void Common::SetMousePosition(int x, int y)
|
||||
{
|
||||
Display* display = XOpenDisplay(nullptr);
|
||||
if (!display)
|
||||
return;
|
||||
|
||||
Window root = DefaultRootWindow(display);
|
||||
XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);
|
||||
XFlush(display);
|
||||
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
||||
static std::function<void(int, int)> fnMouseMoveCb;
|
||||
static std::atomic<bool> trackingMouse = false;
|
||||
static std::thread mouseThread;
|
||||
|
||||
void mouseEventLoop()
|
||||
{
|
||||
Threading::SetNameOfCurrentThread("X11 Mouse Thread");
|
||||
Display* display = XOpenDisplay(nullptr);
|
||||
if (!display)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int opcode, eventcode, error;
|
||||
if (!XQueryExtension(display, "XInputExtension", &opcode, &eventcode, &error))
|
||||
{
|
||||
XCloseDisplay(display);
|
||||
return;
|
||||
}
|
||||
|
||||
const Window root = DefaultRootWindow(display);
|
||||
XIEventMask evmask;
|
||||
unsigned char mask[(XI_LASTEVENT + 7) / 8] = {0};
|
||||
|
||||
evmask.deviceid = XIAllDevices;
|
||||
evmask.mask_len = sizeof(mask);
|
||||
evmask.mask = mask;
|
||||
XISetMask(mask, XI_RawMotion);
|
||||
|
||||
XISelectEvents(display, root, &evmask, 1);
|
||||
XSync(display, False);
|
||||
|
||||
XEvent event;
|
||||
while (trackingMouse)
|
||||
{
|
||||
// XNextEvent is blocking, this is a zombie process risk if no events arrive
|
||||
// while we are trying to shutdown.
|
||||
// https://nrk.neocities.org/articles/x11-timeout-with-xsyncalarm might be
|
||||
// a better solution than using XPending.
|
||||
if (!XPending(display))
|
||||
{
|
||||
Threading::Sleep(1);
|
||||
Threading::SpinWait();
|
||||
continue;
|
||||
}
|
||||
|
||||
XNextEvent(display, &event);
|
||||
if (event.xcookie.type == GenericEvent &&
|
||||
event.xcookie.extension == opcode &&
|
||||
XGetEventData(display, &event.xcookie))
|
||||
{
|
||||
XIRawEvent* raw_event = reinterpret_cast<XIRawEvent*>(event.xcookie.data);
|
||||
if (raw_event->evtype == XI_RawMotion)
|
||||
{
|
||||
Window w;
|
||||
int root_x, root_y, win_x, win_y;
|
||||
unsigned int mask;
|
||||
XQueryPointer(display, root, &w, &w, &root_x, &root_y, &win_x, &win_y, &mask);
|
||||
|
||||
if (fnMouseMoveCb)
|
||||
fnMouseMoveCb(root_x, root_y);
|
||||
}
|
||||
XFreeEventData(display, &event.xcookie);
|
||||
}
|
||||
}
|
||||
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
||||
bool Common::AttachMousePositionCb(std::function<void(int, int)> cb)
|
||||
{
|
||||
fnMouseMoveCb = cb;
|
||||
|
||||
if (trackingMouse)
|
||||
return true;
|
||||
|
||||
trackingMouse = true;
|
||||
mouseThread = std::thread(mouseEventLoop);
|
||||
mouseThread.detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Common::DetachMousePositionCb()
|
||||
{
|
||||
trackingMouse = false;
|
||||
fnMouseMoveCb = nullptr;
|
||||
if (mouseThread.joinable())
|
||||
{
|
||||
mouseThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
bool Common::PlaySoundAsync(const char* path)
|
||||
{
|
||||
#ifdef __linux__
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "common/Console.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/HostSys.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
@@ -86,6 +87,61 @@ bool Common::InhibitScreensaver(bool inhibit)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Common::SetMousePosition(int x, int y)
|
||||
{
|
||||
SetCursorPos(x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
static HHOOK mouseHook = nullptr;
|
||||
static std::function<void(int, int)> fnMouseMoveCb;
|
||||
LRESULT CALLBACK Mousecb(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (nCode >= 0 && wParam == WM_MOUSEMOVE)
|
||||
{
|
||||
MSLLHOOKSTRUCT* mouse = (MSLLHOOKSTRUCT*)lParam;
|
||||
fnMouseMoveCb(mouse->pt.x, mouse->pt.y);
|
||||
}
|
||||
return CallNextHookEx(mouseHook, nCode, wParam, lParam);
|
||||
}
|
||||
*/
|
||||
|
||||
// This (and the above) works, but is not recommended on Windows and is only here for consistency.
|
||||
// Defer to using raw input instead.
|
||||
bool Common::AttachMousePositionCb(std::function<void(int, int)> cb)
|
||||
{
|
||||
/*
|
||||
if (mouseHook)
|
||||
Common::DetachMousePositionCb();
|
||||
|
||||
fnMouseMoveCb = cb;
|
||||
mouseHook = SetWindowsHookEx(WH_MOUSE_LL, Mousecb, GetModuleHandle(NULL), 0);
|
||||
if (!mouseHook)
|
||||
{
|
||||
Console.Warning("Failed to set mouse hook: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(PCSX2_DEBUG) || defined(PCSX2_DEVBUILD)
|
||||
static bool warned = false;
|
||||
if (!warned)
|
||||
{
|
||||
Console.Warning("Mouse hooks are enabled, and this isn't a release build! Using a debugger, or loading symbols, _will_ stall the hook and cause global mouse lag.");
|
||||
warned = true;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
void Common::DetachMousePositionCb()
|
||||
{
|
||||
/*
|
||||
UnhookWindowsHookEx(mouseHook);
|
||||
mouseHook = nullptr;
|
||||
*/
|
||||
}
|
||||
|
||||
bool Common::PlaySoundAsync(const char* path)
|
||||
{
|
||||
const std::wstring wpath = FileSystem::GetWin32Path(path);
|
||||
|
||||
@@ -119,6 +119,12 @@ namespace x86Emitter
|
||||
xImplSimd_DestRegSSE VPD;
|
||||
};
|
||||
|
||||
struct xImplSimd_PBlend
|
||||
{
|
||||
xImplSimd_DestRegImmSSE W;
|
||||
xImplSimd_DestRegSSE VB;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_PMove
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
@@ -500,6 +500,7 @@ namespace x86Emitter
|
||||
extern const xImplSimd_MovHL_RtoR xMOVLH;
|
||||
extern const xImplSimd_MovHL_RtoR xMOVHL;
|
||||
|
||||
extern const xImplSimd_PBlend xPBLEND;
|
||||
extern const xImplSimd_Blend xBLEND;
|
||||
extern const xImplSimd_PMove xPMOVSX;
|
||||
extern const xImplSimd_PMove xPMOVZX;
|
||||
|
||||
@@ -556,12 +556,18 @@ namespace x86Emitter
|
||||
const xImplSimd_MovHL_RtoR xMOVLH = {0x16};
|
||||
const xImplSimd_MovHL_RtoR xMOVHL = {0x12};
|
||||
|
||||
const xImplSimd_PBlend xPBLEND =
|
||||
{
|
||||
{0x66, 0x0e3a}, // W
|
||||
{0x66, 0x1038}, // VB
|
||||
};
|
||||
|
||||
const xImplSimd_Blend xBLEND =
|
||||
{
|
||||
{0x66, 0x0c3a}, // PS
|
||||
{0x66, 0x0d3a}, // PD
|
||||
{0x66, 0x1438}, // VPS
|
||||
{0x66, 0x1538}, // VPD
|
||||
{
|
||||
{0x66, 0x0c3a}, // PS
|
||||
{0x66, 0x0d3a}, // PD
|
||||
{0x66, 0x1438}, // VPS
|
||||
{0x66, 0x1538}, // VPD
|
||||
};
|
||||
|
||||
const xImplSimd_PMove xPMOVSX = {0x2038};
|
||||
|
||||
@@ -4,21 +4,22 @@
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(DepsLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);freetype.lib;libjpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL2.lib;zlib.lib;zstd.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);freetype.lib;jpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL3.lib;zlib.lib;zstd.lib;kddockwidgets-qt62.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<DepsDLLs Include="$(DepsBinDir)freetype.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)harfbuzz.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)libjpeg.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)jpeg62.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)libpng16.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)libsharpyuv.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)libwebp.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)lz4.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)SDL2.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)SDL3.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)shaderc_shared.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)zlib1.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)zstd.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)kddockwidgets-qt62.dll" />
|
||||
</ItemGroup>
|
||||
<Target Name="DepsCopyDLLs"
|
||||
AfterTargets="Build"
|
||||
@@ -31,4 +32,4 @@
|
||||
SkipUnchangedFiles="true"
|
||||
/>
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(QtToolOutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(QtIncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(QtIncludeDir)\QtCore;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(QtIncludeDir)\QtGui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(QtIncludeDir)\QtWidgets;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(QtLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
|
||||
@@ -169,11 +169,25 @@ void Host::SetDefaultUISettings(SettingsInterface& si)
|
||||
// nothing
|
||||
}
|
||||
|
||||
bool Host::LocaleCircleConfirm()
|
||||
{
|
||||
// not running any UI, so no settings requests will come in
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<ProgressCallback> Host::CreateHostProgressCallback()
|
||||
{
|
||||
return ProgressCallback::CreateNullProgressCallback();
|
||||
}
|
||||
|
||||
void Host::ReportInfoAsync(const std::string_view title, const std::string_view message)
|
||||
{
|
||||
if (!title.empty() && !message.empty())
|
||||
INFO_LOG("ReportInfoAsync: {}: {}", title, message);
|
||||
else if (!message.empty())
|
||||
INFO_LOG("ReportInfoAsync: {}", message);
|
||||
}
|
||||
|
||||
void Host::ReportErrorAsync(const std::string_view title, const std::string_view message)
|
||||
{
|
||||
if (!title.empty() && !message.empty())
|
||||
@@ -246,7 +260,7 @@ void Host::BeginPresentFrame()
|
||||
GSJoinSnapshotThreads();
|
||||
|
||||
// queue dumping of this frame
|
||||
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
|
||||
std::string dump_path(fmt::format("{}_frame{:05}.png", s_output_prefix, s_dump_frame_number));
|
||||
GSQueueSnapshot(dump_path);
|
||||
}
|
||||
|
||||
@@ -443,8 +457,17 @@ static void PrintCommandLineHelp(const char* progname)
|
||||
std::fprintf(stderr, " -help: Displays this information and exits.\n");
|
||||
std::fprintf(stderr, " -version: Displays version information and exits.\n");
|
||||
std::fprintf(stderr, " -dumpdir <dir>: Frame dump directory (will be dumped as filename_frameN.png).\n");
|
||||
std::fprintf(stderr, " -dump [rt|tex|z|f|a|i]: Enabling dumping of render target, texture, z buffer, frame, "
|
||||
"alphas, and info (context, vertices), respectively, per draw. Generates lots of data.\n");
|
||||
std::fprintf(stderr, " -dumprange N[,L,B]: Start dumping from draw N (base 0), stops after L draws, and only "
|
||||
"those draws that are multiples of B (intersection of -dumprange and -dumprangef used)."
|
||||
"Defaults to 0,-1,1 (all draws). Only used if -dump used.\n");
|
||||
std::fprintf(stderr, " -dumprangef NF[,LF,BF]: Start dumping from frame NF (base 0), stops after LF frames, "
|
||||
"and only those frames that are multiples of BF (intersection of -dumprange and -dumprangef used).\n"
|
||||
"Defaults to 0,-1,1 (all frames). Only used if -dump is used.\n");
|
||||
std::fprintf(stderr, " -loop <count>: Loops dump playback N times. Defaults to 1. 0 will loop infinitely.\n");
|
||||
std::fprintf(stderr, " -renderer <renderer>: Sets the graphics renderer. Defaults to Auto.\n");
|
||||
std::fprintf(stderr, " -swthreads <threads>: Sets the number of threads for the software renderer.\n");
|
||||
std::fprintf(stderr, " -window: Forces a window to be displayed.\n");
|
||||
std::fprintf(stderr, " -surfaceless: Disables showing a window.\n");
|
||||
std::fprintf(stderr, " -logfile <filename>: Writes emu log to filename.\n");
|
||||
@@ -465,6 +488,7 @@ void GSRunner::InitializeConsole()
|
||||
|
||||
bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& params)
|
||||
{
|
||||
std::string dumpdir; // Save from argument -dumpdir for creating sub-directories
|
||||
bool no_more_args = false;
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
@@ -485,7 +509,7 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-dumpdir"))
|
||||
{
|
||||
s_output_prefix = StringUtil::StripWhitespace(argv[++i]);
|
||||
dumpdir = s_output_prefix = StringUtil::StripWhitespace(argv[++i]);
|
||||
if (s_output_prefix.empty())
|
||||
{
|
||||
Console.Error("Invalid dump directory specified.");
|
||||
@@ -500,6 +524,86 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-dump"))
|
||||
{
|
||||
std::string str(argv[++i]);
|
||||
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "dump", true);
|
||||
|
||||
if (str.find("rt") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveRT", true);
|
||||
if (str.find("f") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveFrame", true);
|
||||
if (str.find("tex") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveTexture", true);
|
||||
if (str.find("z") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveDepth", true);
|
||||
if (str.find("a") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveAlpha", true);
|
||||
if (str.find("i") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveInfo", true);
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-dumprange"))
|
||||
{
|
||||
std::string str(argv[++i]);
|
||||
|
||||
std::vector<std::string_view> split = StringUtil::SplitString(str, ',');
|
||||
int start = 0;
|
||||
int num = -1;
|
||||
int by = 1;
|
||||
if (split.size() > 0)
|
||||
{
|
||||
start = StringUtil::FromChars<int>(split[0]).value_or(0);
|
||||
}
|
||||
if (split.size() > 1)
|
||||
{
|
||||
num = StringUtil::FromChars<int>(split[1]).value_or(-1);
|
||||
}
|
||||
if (split.size() > 2)
|
||||
{
|
||||
by = std::max(1, StringUtil::FromChars<int>(split[2]).value_or(1));
|
||||
}
|
||||
s_settings_interface.SetIntValue("EmuCore/GS", "SaveDrawStart", start);
|
||||
s_settings_interface.SetIntValue("EmuCore/GS", "SaveDrawCount", num);
|
||||
s_settings_interface.SetIntValue("EmuCore/GS", "SaveDrawBy", by);
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-dumprangef"))
|
||||
{
|
||||
std::string str(argv[++i]);
|
||||
|
||||
std::vector<std::string_view> split = StringUtil::SplitString(str, ',');
|
||||
int start = 0;
|
||||
int num = -1;
|
||||
int by = 1;
|
||||
if (split.size() > 0)
|
||||
{
|
||||
start = StringUtil::FromChars<int>(split[0]).value_or(0);
|
||||
}
|
||||
if (split.size() > 1)
|
||||
{
|
||||
num = StringUtil::FromChars<int>(split[1]).value_or(-1);
|
||||
}
|
||||
if (split.size() > 2)
|
||||
{
|
||||
by = std::max(1, StringUtil::FromChars<int>(split[2]).value_or(1));
|
||||
}
|
||||
s_settings_interface.SetIntValue("EmuCore/GS", "SaveFrameStart", start);
|
||||
s_settings_interface.SetIntValue("EmuCore/GS", "SaveFrameCount", num);
|
||||
s_settings_interface.SetIntValue("EmuCore/GS", "SaveFrameBy", by);
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-dumpdirhw"))
|
||||
{
|
||||
s_settings_interface.SetStringValue("EmuCore/GS", "HWDumpDirectory", argv[++i]);
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-dumpdirsw"))
|
||||
{
|
||||
s_settings_interface.SetStringValue("EmuCore/GS", "SWDumpDirectory", argv[++i]);
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-loop"))
|
||||
{
|
||||
s_loop_count = StringUtil::FromChars<s32>(argv[++i]).value_or(0);
|
||||
@@ -543,6 +647,19 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
|
||||
s_settings_interface.SetIntValue("EmuCore/GS", "Renderer", static_cast<int>(type));
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-swthreads"))
|
||||
{
|
||||
const int swthreads = StringUtil::FromChars<int>(argv[++i]).value_or(0);
|
||||
if (swthreads < 0)
|
||||
{
|
||||
Console.WriteLn("Invalid number of software threads");
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLn(fmt::format("Setting number of software threads to {}", swthreads));
|
||||
s_settings_interface.SetIntValue("EmuCore/GS", "SWExtraThreads", swthreads);
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-renderhacks"))
|
||||
{
|
||||
std::string str(argv[++i]);
|
||||
@@ -643,6 +760,18 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s_settings_interface.GetBoolValue("EmuCore/GS", "dump") && !dumpdir.empty())
|
||||
{
|
||||
if (s_settings_interface.GetStringValue("EmuCore/GS", "HWDumpDirectory").empty())
|
||||
s_settings_interface.SetStringValue("EmuCore/GS", "HWDumpDirectory", dumpdir.c_str());
|
||||
if (s_settings_interface.GetStringValue("EmuCore/GS", "SWDumpDirectory").empty())
|
||||
s_settings_interface.SetStringValue("EmuCore/GS", "SWDumpDirectory", dumpdir.c_str());
|
||||
|
||||
// Disable saving frames with SaveSnapshotToMemory()
|
||||
// Instead we save more "raw" snapshots when using -dump.
|
||||
s_output_prefix = "";
|
||||
}
|
||||
|
||||
// set up the frame dump directory
|
||||
if (!s_output_prefix.empty())
|
||||
{
|
||||
|
||||
@@ -89,6 +89,16 @@ QString AboutDialog::getThirdPartyLicensesUrl()
|
||||
return GetDocFileUrl("ThirdPartyLicenses.html");
|
||||
}
|
||||
|
||||
QString AboutDialog::getWikiUrl()
|
||||
{
|
||||
return QString::fromUtf8(PCSX2_WIKI_URL);
|
||||
}
|
||||
|
||||
QString AboutDialog::getDocumentationUrl()
|
||||
{
|
||||
return QString::fromUtf8(PCSX2_DOCUMENTATION_URL);
|
||||
}
|
||||
|
||||
QString AboutDialog::getDiscordServerUrl()
|
||||
{
|
||||
return QString::fromUtf8(PCSX2_DISCORD_URL);
|
||||
|
||||
@@ -19,6 +19,8 @@ public:
|
||||
static QString getGitHubRepositoryUrl();
|
||||
static QString getLicenseUrl();
|
||||
static QString getThirdPartyLicensesUrl();
|
||||
static QString getWikiUrl();
|
||||
static QString getDocumentationUrl();
|
||||
static QString getDiscordServerUrl();
|
||||
|
||||
static void showHTMLDialog(QWidget* parent, const QString& title, const QString& url);
|
||||
|
||||
@@ -86,6 +86,9 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Settings/DebugAnalysisSettingsWidget.cpp
|
||||
Settings/DebugAnalysisSettingsWidget.h
|
||||
Settings/DebugAnalysisSettingsWidget.ui
|
||||
Settings/DebugUserInterfaceSettingsWidget.cpp
|
||||
Settings/DebugUserInterfaceSettingsWidget.h
|
||||
Settings/DebugUserInterfaceSettingsWidget.ui
|
||||
Settings/DebugSettingsWidget.cpp
|
||||
Settings/DebugSettingsWidget.h
|
||||
Settings/DebugSettingsWidget.ui
|
||||
@@ -158,37 +161,66 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Debugger/AnalysisOptionsDialog.cpp
|
||||
Debugger/AnalysisOptionsDialog.h
|
||||
Debugger/AnalysisOptionsDialog.ui
|
||||
Debugger/CpuWidget.cpp
|
||||
Debugger/CpuWidget.h
|
||||
Debugger/CpuWidget.ui
|
||||
Debugger/DebuggerSettingsManager.cpp
|
||||
Debugger/DebuggerSettingsManager.h
|
||||
Debugger/DebuggerEvents.h
|
||||
Debugger/DebuggerWidget.cpp
|
||||
Debugger/DebuggerWidget.h
|
||||
Debugger/DebuggerWindow.cpp
|
||||
Debugger/DebuggerWindow.h
|
||||
Debugger/DebuggerWindow.ui
|
||||
Debugger/DisassemblyWidget.cpp
|
||||
Debugger/DisassemblyWidget.h
|
||||
Debugger/DisassemblyWidget.ui
|
||||
Debugger/MemorySearchWidget.cpp
|
||||
Debugger/MemorySearchWidget.h
|
||||
Debugger/MemorySearchWidget.ui
|
||||
Debugger/MemoryViewWidget.cpp
|
||||
Debugger/MemoryViewWidget.h
|
||||
Debugger/MemoryViewWidget.ui
|
||||
Debugger/JsonValueWrapper.h
|
||||
Debugger/RegisterWidget.cpp
|
||||
Debugger/RegisterWidget.h
|
||||
Debugger/RegisterWidget.ui
|
||||
Debugger/BreakpointDialog.cpp
|
||||
Debugger/BreakpointDialog.h
|
||||
Debugger/BreakpointDialog.ui
|
||||
Debugger/Models/BreakpointModel.cpp
|
||||
Debugger/Models/BreakpointModel.h
|
||||
Debugger/Models/ThreadModel.cpp
|
||||
Debugger/Models/ThreadModel.h
|
||||
Debugger/Models/StackModel.cpp
|
||||
Debugger/Models/StackModel.h
|
||||
Debugger/Models/SavedAddressesModel.cpp
|
||||
Debugger/Models/SavedAddressesModel.h
|
||||
Debugger/StackModel.cpp
|
||||
Debugger/StackModel.h
|
||||
Debugger/StackWidget.cpp
|
||||
Debugger/StackWidget.h
|
||||
Debugger/ThreadModel.cpp
|
||||
Debugger/ThreadModel.h
|
||||
Debugger/ThreadWidget.cpp
|
||||
Debugger/ThreadWidget.h
|
||||
Debugger/Breakpoints/BreakpointDialog.cpp
|
||||
Debugger/Breakpoints/BreakpointDialog.h
|
||||
Debugger/Breakpoints/BreakpointDialog.ui
|
||||
Debugger/Breakpoints/BreakpointModel.cpp
|
||||
Debugger/Breakpoints/BreakpointModel.h
|
||||
Debugger/Breakpoints/BreakpointWidget.cpp
|
||||
Debugger/Breakpoints/BreakpointWidget.h
|
||||
Debugger/Breakpoints/BreakpointWidget.ui
|
||||
Debugger/Docking/DockLayout.cpp
|
||||
Debugger/Docking/DockLayout.h
|
||||
Debugger/Docking/DockManager.cpp
|
||||
Debugger/Docking/DockManager.h
|
||||
Debugger/Docking/DockTables.cpp
|
||||
Debugger/Docking/DockTables.h
|
||||
Debugger/Docking/DockUtils.cpp
|
||||
Debugger/Docking/DockUtils.h
|
||||
Debugger/Docking/DockViews.cpp
|
||||
Debugger/Docking/DockViews.h
|
||||
Debugger/Docking/DropIndicators.cpp
|
||||
Debugger/Docking/DropIndicators.h
|
||||
Debugger/Docking/LayoutEditorDialog.cpp
|
||||
Debugger/Docking/LayoutEditorDialog.h
|
||||
Debugger/Docking/LayoutEditorDialog.ui
|
||||
Debugger/Docking/NoLayoutsWidget.cpp
|
||||
Debugger/Docking/NoLayoutsWidget.h
|
||||
Debugger/Docking/NoLayoutsWidget.ui
|
||||
Debugger/Memory/MemorySearchWidget.cpp
|
||||
Debugger/Memory/MemorySearchWidget.h
|
||||
Debugger/Memory/MemorySearchWidget.ui
|
||||
Debugger/Memory/MemoryViewWidget.cpp
|
||||
Debugger/Memory/MemoryViewWidget.h
|
||||
Debugger/Memory/MemoryViewWidget.ui
|
||||
Debugger/Memory/SavedAddressesModel.cpp
|
||||
Debugger/Memory/SavedAddressesModel.h
|
||||
Debugger/Memory/SavedAddressesWidget.cpp
|
||||
Debugger/Memory/SavedAddressesWidget.h
|
||||
Debugger/Memory/SavedAddressesWidget.ui
|
||||
Debugger/SymbolTree/NewSymbolDialogs.cpp
|
||||
Debugger/SymbolTree/NewSymbolDialogs.h
|
||||
Debugger/SymbolTree/NewSymbolDialog.ui
|
||||
@@ -232,6 +264,7 @@ target_link_libraries(pcsx2-qt PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
KDAB::kddockwidgets
|
||||
)
|
||||
|
||||
# Our Qt builds may have exceptions on, so force them off.
|
||||
|
||||
@@ -29,7 +29,7 @@ void ColorPickerButton::setColor(u32 rgb)
|
||||
|
||||
void ColorPickerButton::updateBackgroundColor()
|
||||
{
|
||||
setStyleSheet(QStringLiteral("background-color: #%1;").arg(static_cast<uint>(m_color), 8, 16, QChar('0')));
|
||||
setStyleSheet(QStringLiteral("background-color: #%1;").arg(static_cast<uint>(m_color), 6, 16, QChar('0')));
|
||||
}
|
||||
|
||||
void ColorPickerButton::onClicked()
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
#include "ui_BreakpointDialog.h"
|
||||
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
#include "BreakpointModel.h"
|
||||
|
||||
#include "Models/BreakpointModel.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
|
||||
#include <QtWidgets/QDialog>
|
||||
|
||||
@@ -3,21 +3,48 @@
|
||||
|
||||
#include "BreakpointModel.h"
|
||||
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
#include "Debugger/DebuggerSettingsManager.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
#include "DebugTools/DisassemblyManager.h"
|
||||
#include "common/Console.h"
|
||||
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
std::map<BreakPointCpu, BreakpointModel*> BreakpointModel::s_instances;
|
||||
|
||||
BreakpointModel::BreakpointModel(DebugInterface& cpu, QObject* parent)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_cpu(cpu)
|
||||
{
|
||||
if (m_cpu.getCpuType() == BREAKPOINT_EE)
|
||||
{
|
||||
connect(g_emu_thread, &EmuThread::onGameChanged, this, [this](const QString& title) {
|
||||
if (title.isEmpty())
|
||||
return;
|
||||
|
||||
if (rowCount() == 0)
|
||||
DebuggerSettingsManager::loadGameSettings(this);
|
||||
});
|
||||
|
||||
DebuggerSettingsManager::loadGameSettings(this);
|
||||
}
|
||||
|
||||
connect(this, &BreakpointModel::dataChanged, this, &BreakpointModel::refreshData);
|
||||
}
|
||||
|
||||
BreakpointModel* BreakpointModel::getInstance(DebugInterface& cpu)
|
||||
{
|
||||
auto iterator = s_instances.find(cpu.getCpuType());
|
||||
if (iterator == s_instances.end())
|
||||
iterator = s_instances.emplace(cpu.getCpuType(), new BreakpointModel(cpu)).first;
|
||||
|
||||
return iterator->second;
|
||||
}
|
||||
|
||||
int BreakpointModel::rowCount(const QModelIndex&) const
|
||||
@@ -32,10 +59,14 @@ int BreakpointModel::columnCount(const QModelIndex&) const
|
||||
|
||||
QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
size_t row = static_cast<size_t>(index.row());
|
||||
if (!index.isValid() || row >= m_breakpoints.size())
|
||||
return QVariant();
|
||||
|
||||
const BreakpointMemcheck& bp_mc = m_breakpoints[row];
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
auto bp_mc = m_breakpoints.at(index.row());
|
||||
|
||||
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
|
||||
{
|
||||
switch (index.column())
|
||||
@@ -87,8 +118,6 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
}
|
||||
else if (role == BreakpointModel::DataRole)
|
||||
{
|
||||
auto bp_mc = m_breakpoints.at(index.row());
|
||||
|
||||
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
|
||||
{
|
||||
switch (index.column())
|
||||
@@ -133,8 +162,6 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
}
|
||||
else if (role == BreakpointModel::ExportRole)
|
||||
{
|
||||
auto bp_mc = m_breakpoints.at(index.row());
|
||||
|
||||
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
|
||||
{
|
||||
switch (index.column())
|
||||
@@ -181,8 +208,6 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (index.column() == 0)
|
||||
{
|
||||
auto bp_mc = m_breakpoints.at(index.row());
|
||||
|
||||
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
|
||||
{
|
||||
return bp->enabled ? Qt::CheckState::Checked : Qt::CheckState::Unchecked;
|
||||
@@ -273,12 +298,14 @@ Qt::ItemFlags BreakpointModel::flags(const QModelIndex& index) const
|
||||
|
||||
bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||
{
|
||||
std::string error;
|
||||
size_t row = static_cast<size_t>(index.row());
|
||||
if (!index.isValid() || row >= m_breakpoints.size())
|
||||
return false;
|
||||
|
||||
const BreakpointMemcheck& bp_mc = m_breakpoints[row];
|
||||
|
||||
if (role == Qt::CheckStateRole && index.column() == BreakpointColumns::ENABLED)
|
||||
{
|
||||
auto bp_mc = m_breakpoints.at(index.row());
|
||||
|
||||
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
|
||||
{
|
||||
Host::RunOnCPUThread([cpu = this->m_cpu.getCpuType(), bp = *bp, enabled = value.toBool()] {
|
||||
@@ -297,8 +324,6 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
}
|
||||
else if (role == Qt::EditRole && index.column() == BreakpointColumns::CONDITION)
|
||||
{
|
||||
auto bp_mc = m_breakpoints.at(index.row());
|
||||
|
||||
if (auto* bp = std::get_if<BreakPoint>(&bp_mc))
|
||||
{
|
||||
const QString condValue = value.toString();
|
||||
@@ -316,6 +341,7 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
{
|
||||
PostfixExpression expr;
|
||||
|
||||
std::string error;
|
||||
if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr, error))
|
||||
{
|
||||
QMessageBox::warning(nullptr, "Condition Error", QString::fromStdString(error));
|
||||
@@ -349,6 +375,7 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
{
|
||||
PostfixExpression expr;
|
||||
|
||||
std::string error;
|
||||
if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr, error))
|
||||
{
|
||||
QMessageBox::warning(nullptr, "Condition Error", QString::fromStdString(error));
|
||||
@@ -34,8 +34,7 @@ public:
|
||||
ExportRole = Qt::UserRole + 1,
|
||||
};
|
||||
|
||||
static constexpr QHeaderView::ResizeMode HeaderResizeModes[BreakpointColumns::COLUMN_COUNT] =
|
||||
{
|
||||
static constexpr QHeaderView::ResizeMode HeaderResizeModes[BreakpointColumns::COLUMN_COUNT] = {
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
@@ -45,7 +44,7 @@ public:
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
};
|
||||
|
||||
explicit BreakpointModel(DebugInterface& cpu, QObject* parent = nullptr);
|
||||
static BreakpointModel* getInstance(DebugInterface& cpu);
|
||||
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
@@ -63,6 +62,10 @@ public:
|
||||
void clear();
|
||||
|
||||
private:
|
||||
BreakpointModel(DebugInterface& cpu, QObject* parent = nullptr);
|
||||
|
||||
DebugInterface& m_cpu;
|
||||
std::vector<BreakpointMemcheck> m_breakpoints;
|
||||
|
||||
static std::map<BreakPointCpu, BreakpointModel*> s_instances;
|
||||
};
|
||||
176
pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.cpp
Normal file
176
pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "BreakpointWidget.h"
|
||||
|
||||
#include "QtUtils.h"
|
||||
#include "Debugger/DebuggerSettingsManager.h"
|
||||
#include "BreakpointDialog.h"
|
||||
#include "BreakpointModel.h"
|
||||
|
||||
#include <QtGui/QClipboard>
|
||||
|
||||
BreakpointWidget::BreakpointWidget(const DebuggerWidgetParameters& parameters)
|
||||
: DebuggerWidget(parameters, DISALLOW_MULTIPLE_INSTANCES)
|
||||
, m_model(BreakpointModel::getInstance(cpu()))
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
m_ui.breakpointList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_ui.breakpointList, &QTableView::customContextMenuRequested, this, &BreakpointWidget::openContextMenu);
|
||||
connect(m_ui.breakpointList, &QTableView::doubleClicked, this, &BreakpointWidget::onDoubleClicked);
|
||||
|
||||
m_ui.breakpointList->setModel(m_model);
|
||||
for (std::size_t i = 0; auto mode : BreakpointModel::HeaderResizeModes)
|
||||
{
|
||||
m_ui.breakpointList->horizontalHeader()->setSectionResizeMode(i, mode);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void BreakpointWidget::onDoubleClicked(const QModelIndex& index)
|
||||
{
|
||||
if (index.isValid() && index.column() == BreakpointModel::OFFSET)
|
||||
goToInDisassembler(m_model->data(index, BreakpointModel::DataRole).toUInt(), true);
|
||||
}
|
||||
|
||||
void BreakpointWidget::openContextMenu(QPoint pos)
|
||||
{
|
||||
QMenu* menu = new QMenu(m_ui.breakpointList);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (cpu().isAlive())
|
||||
{
|
||||
QAction* newAction = menu->addAction(tr("New"));
|
||||
connect(newAction, &QAction::triggered, this, &BreakpointWidget::contextNew);
|
||||
|
||||
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
|
||||
|
||||
if (selModel->hasSelection())
|
||||
{
|
||||
QAction* editAction = menu->addAction(tr("Edit"));
|
||||
connect(editAction, &QAction::triggered, this, &BreakpointWidget::contextEdit);
|
||||
|
||||
if (selModel->selectedIndexes().count() == 1)
|
||||
{
|
||||
QAction* copyAction = menu->addAction(tr("Copy"));
|
||||
connect(copyAction, &QAction::triggered, this, &BreakpointWidget::contextCopy);
|
||||
}
|
||||
|
||||
QAction* deleteAction = menu->addAction(tr("Delete"));
|
||||
connect(deleteAction, &QAction::triggered, this, &BreakpointWidget::contextDelete);
|
||||
}
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
if (m_model->rowCount() > 0)
|
||||
{
|
||||
QAction* actionExport = menu->addAction(tr("Copy all as CSV"));
|
||||
connect(actionExport, &QAction::triggered, [this]() {
|
||||
// It's important to use the Export Role here to allow pasting to be translation agnostic
|
||||
QGuiApplication::clipboard()->setText(
|
||||
QtUtils::AbstractItemModelToCSV(m_model, BreakpointModel::ExportRole, true));
|
||||
});
|
||||
}
|
||||
|
||||
if (cpu().isAlive())
|
||||
{
|
||||
QAction* actionImport = menu->addAction(tr("Paste from CSV"));
|
||||
connect(actionImport, &QAction::triggered, this, &BreakpointWidget::contextPasteCSV);
|
||||
|
||||
if (cpu().getCpuType() == BREAKPOINT_EE)
|
||||
{
|
||||
QAction* actionLoad = menu->addAction(tr("Load from Settings"));
|
||||
connect(actionLoad, &QAction::triggered, [this]() {
|
||||
m_model->clear();
|
||||
DebuggerSettingsManager::loadGameSettings(m_model);
|
||||
});
|
||||
|
||||
QAction* actionSave = menu->addAction(tr("Save to Settings"));
|
||||
connect(actionSave, &QAction::triggered, this, &BreakpointWidget::saveBreakpointsToDebuggerSettings);
|
||||
}
|
||||
}
|
||||
|
||||
menu->popup(m_ui.breakpointList->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void BreakpointWidget::contextCopy()
|
||||
{
|
||||
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
|
||||
|
||||
if (!selModel->hasSelection())
|
||||
return;
|
||||
|
||||
QGuiApplication::clipboard()->setText(m_model->data(selModel->currentIndex()).toString());
|
||||
}
|
||||
|
||||
void BreakpointWidget::contextDelete()
|
||||
{
|
||||
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
|
||||
|
||||
if (!selModel->hasSelection())
|
||||
return;
|
||||
|
||||
QModelIndexList rows = selModel->selectedIndexes();
|
||||
|
||||
std::sort(rows.begin(), rows.end(), [](const QModelIndex& a, const QModelIndex& b) {
|
||||
return a.row() > b.row();
|
||||
});
|
||||
|
||||
for (const QModelIndex& index : rows)
|
||||
{
|
||||
m_model->removeRows(index.row(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
void BreakpointWidget::contextNew()
|
||||
{
|
||||
BreakpointDialog* bpDialog = new BreakpointDialog(this, &cpu(), *m_model);
|
||||
bpDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
bpDialog->show();
|
||||
}
|
||||
|
||||
void BreakpointWidget::contextEdit()
|
||||
{
|
||||
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
|
||||
|
||||
if (!selModel->hasSelection())
|
||||
return;
|
||||
|
||||
const int selectedRow = selModel->selectedIndexes().first().row();
|
||||
|
||||
auto bpObject = m_model->at(selectedRow);
|
||||
|
||||
BreakpointDialog* bpDialog = new BreakpointDialog(this, &cpu(), *m_model, bpObject, selectedRow);
|
||||
bpDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
bpDialog->show();
|
||||
}
|
||||
|
||||
void BreakpointWidget::contextPasteCSV()
|
||||
{
|
||||
QString csv = QGuiApplication::clipboard()->text();
|
||||
// Skip header
|
||||
csv = csv.mid(csv.indexOf('\n') + 1);
|
||||
|
||||
for (const QString& line : csv.split('\n'))
|
||||
{
|
||||
QStringList fields;
|
||||
// In order to handle text with commas in them we must wrap values in quotes to mark
|
||||
// where a value starts and end so that text commas aren't identified as delimiters.
|
||||
// So matches each quote pair, parse it out, and removes the quotes to get the value.
|
||||
QRegularExpression eachQuotePair(R"("([^"]|\\.)*")");
|
||||
QRegularExpressionMatchIterator it = eachQuotePair.globalMatch(line);
|
||||
while (it.hasNext())
|
||||
{
|
||||
QRegularExpressionMatch match = it.next();
|
||||
QString matchedValue = match.captured(0);
|
||||
fields << matchedValue.mid(1, matchedValue.length() - 2);
|
||||
}
|
||||
m_model->loadBreakpointFromFieldList(fields);
|
||||
}
|
||||
}
|
||||
|
||||
void BreakpointWidget::saveBreakpointsToDebuggerSettings()
|
||||
{
|
||||
DebuggerSettingsManager::saveGameSettings(m_model);
|
||||
}
|
||||
41
pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.h
Normal file
41
pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_BreakpointWidget.h"
|
||||
|
||||
#include "BreakpointModel.h"
|
||||
|
||||
#include "Debugger/DebuggerWidget.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/DisassemblyManager.h"
|
||||
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QTabBar>
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
class BreakpointWidget : public DebuggerWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BreakpointWidget(const DebuggerWidgetParameters& parameters);
|
||||
|
||||
void onDoubleClicked(const QModelIndex& index);
|
||||
void openContextMenu(QPoint pos);
|
||||
|
||||
void contextCopy();
|
||||
void contextDelete();
|
||||
void contextNew();
|
||||
void contextEdit();
|
||||
void contextPasteCSV();
|
||||
|
||||
void saveBreakpointsToDebuggerSettings();
|
||||
|
||||
private:
|
||||
Ui::BreakpointWidget m_ui;
|
||||
|
||||
BreakpointModel* m_model;
|
||||
};
|
||||
39
pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.ui
Normal file
39
pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.ui
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BreakpointWidget</class>
|
||||
<widget class="QWidget" name="BreakpointWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableView" name="breakpointList"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,732 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "CpuWidget.h"
|
||||
|
||||
#include "DisassemblyWidget.h"
|
||||
#include "BreakpointDialog.h"
|
||||
#include "Models/BreakpointModel.h"
|
||||
#include "Models/ThreadModel.h"
|
||||
#include "Models/SavedAddressesModel.h"
|
||||
#include "Debugger/DebuggerSettingsManager.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
#include "DebugTools/MipsStackWalk.h"
|
||||
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include "common/Console.h"
|
||||
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include <QtCore/QFutureWatcher>
|
||||
#include <QtCore/QRegularExpression>
|
||||
#include <QtCore/QRegularExpressionMatchIterator>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtWidgets/QScrollBar>
|
||||
|
||||
using namespace QtUtils;
|
||||
using namespace MipsStackWalk;
|
||||
|
||||
CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
|
||||
: m_cpu(cpu)
|
||||
, m_bpModel(cpu)
|
||||
, m_threadModel(cpu)
|
||||
, m_stackModel(cpu)
|
||||
, m_savedAddressesModel(cpu)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
connect(g_emu_thread, &EmuThread::onVMPaused, this, &CpuWidget::onVMPaused);
|
||||
connect(g_emu_thread, &EmuThread::onGameChanged, this, [this](const QString& title) {
|
||||
if (title.isEmpty())
|
||||
return;
|
||||
// Don't overwrite users BPs/Saved Addresses unless they have a clean state.
|
||||
if (m_bpModel.rowCount() == 0)
|
||||
DebuggerSettingsManager::loadGameSettings(&m_bpModel);
|
||||
if (m_savedAddressesModel.rowCount() == 0)
|
||||
DebuggerSettingsManager::loadGameSettings(&m_savedAddressesModel);
|
||||
});
|
||||
|
||||
connect(m_ui.registerWidget, &RegisterWidget::gotoInDisasm, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddress);
|
||||
connect(m_ui.memoryviewWidget, &MemoryViewWidget::gotoInDisasm, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddress);
|
||||
connect(m_ui.memoryviewWidget, &MemoryViewWidget::addToSavedAddresses, this, &CpuWidget::addAddressToSavedAddressesList);
|
||||
|
||||
connect(m_ui.registerWidget, &RegisterWidget::gotoInMemory, this, &CpuWidget::onGotoInMemory);
|
||||
connect(m_ui.disassemblyWidget, &DisassemblyWidget::gotoInMemory, this, &CpuWidget::onGotoInMemory);
|
||||
|
||||
connect(m_ui.memoryviewWidget, &MemoryViewWidget::VMUpdate, this, &CpuWidget::reloadCPUWidgets);
|
||||
connect(m_ui.registerWidget, &RegisterWidget::VMUpdate, this, &CpuWidget::reloadCPUWidgets);
|
||||
connect(m_ui.disassemblyWidget, &DisassemblyWidget::VMUpdate, this, &CpuWidget::reloadCPUWidgets);
|
||||
|
||||
connect(m_ui.disassemblyWidget, &DisassemblyWidget::breakpointsChanged, this, &CpuWidget::updateBreakpoints);
|
||||
|
||||
connect(m_ui.breakpointList, &QTableView::customContextMenuRequested, this, &CpuWidget::onBPListContextMenu);
|
||||
connect(m_ui.breakpointList, &QTableView::doubleClicked, this, &CpuWidget::onBPListDoubleClicked);
|
||||
|
||||
m_ui.breakpointList->setModel(&m_bpModel);
|
||||
for (std::size_t i = 0; auto mode : BreakpointModel::HeaderResizeModes)
|
||||
{
|
||||
m_ui.breakpointList->horizontalHeader()->setSectionResizeMode(i, mode);
|
||||
i++;
|
||||
}
|
||||
|
||||
connect(&m_bpModel, &BreakpointModel::dataChanged, this, &CpuWidget::updateBreakpoints);
|
||||
|
||||
connect(m_ui.threadList, &QTableView::customContextMenuRequested, this, &CpuWidget::onThreadListContextMenu);
|
||||
connect(m_ui.threadList, &QTableView::doubleClicked, this, &CpuWidget::onThreadListDoubleClick);
|
||||
|
||||
m_threadProxyModel.setSourceModel(&m_threadModel);
|
||||
m_threadProxyModel.setSortRole(Qt::UserRole);
|
||||
m_ui.threadList->setModel(&m_threadProxyModel);
|
||||
m_ui.threadList->setSortingEnabled(true);
|
||||
m_ui.threadList->sortByColumn(ThreadModel::ThreadColumns::ID, Qt::SortOrder::AscendingOrder);
|
||||
for (std::size_t i = 0; auto mode : ThreadModel::HeaderResizeModes)
|
||||
{
|
||||
m_ui.threadList->horizontalHeader()->setSectionResizeMode(i, mode);
|
||||
i++;
|
||||
}
|
||||
|
||||
connect(m_ui.stackList, &QTableView::customContextMenuRequested, this, &CpuWidget::onStackListContextMenu);
|
||||
connect(m_ui.stackList, &QTableView::doubleClicked, this, &CpuWidget::onStackListDoubleClick);
|
||||
|
||||
m_ui.stackList->setModel(&m_stackModel);
|
||||
for (std::size_t i = 0; auto mode : StackModel::HeaderResizeModes)
|
||||
{
|
||||
m_ui.stackList->horizontalHeader()->setSectionResizeMode(i, mode);
|
||||
i++;
|
||||
}
|
||||
|
||||
m_ui.disassemblyWidget->SetCpu(&cpu);
|
||||
m_ui.registerWidget->SetCpu(&cpu);
|
||||
m_ui.memoryviewWidget->SetCpu(&cpu);
|
||||
|
||||
this->repaint();
|
||||
|
||||
m_ui.savedAddressesList->setModel(&m_savedAddressesModel);
|
||||
m_ui.savedAddressesList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_ui.savedAddressesList, &QTableView::customContextMenuRequested, this, &CpuWidget::onSavedAddressesListContextMenu);
|
||||
for (std::size_t i = 0; auto mode : SavedAddressesModel::HeaderResizeModes)
|
||||
{
|
||||
m_ui.savedAddressesList->horizontalHeader()->setSectionResizeMode(i++, mode);
|
||||
}
|
||||
QTableView* savedAddressesTableView = m_ui.savedAddressesList;
|
||||
connect(m_ui.savedAddressesList->model(), &QAbstractItemModel::dataChanged, [savedAddressesTableView](const QModelIndex& topLeft) {
|
||||
savedAddressesTableView->resizeColumnToContents(topLeft.column());
|
||||
});
|
||||
|
||||
setupSymbolTrees();
|
||||
|
||||
DebuggerSettingsManager::loadGameSettings(&m_bpModel);
|
||||
DebuggerSettingsManager::loadGameSettings(&m_savedAddressesModel);
|
||||
|
||||
connect(m_ui.memorySearchWidget, &MemorySearchWidget::addAddressToSavedAddressesList, this, &CpuWidget::addAddressToSavedAddressesList);
|
||||
connect(m_ui.memorySearchWidget, &MemorySearchWidget::goToAddressInDisassemblyView,
|
||||
[this](u32 address) { m_ui.disassemblyWidget->gotoAddress(address, true); });
|
||||
connect(m_ui.memorySearchWidget, &MemorySearchWidget::goToAddressInMemoryView, m_ui.memoryviewWidget, &MemoryViewWidget::gotoAddress);
|
||||
connect(m_ui.memorySearchWidget, &MemorySearchWidget::switchToMemoryViewTab,
|
||||
[this]() { m_ui.tabWidget->setCurrentWidget(m_ui.tab_memory); });
|
||||
m_ui.memorySearchWidget->setCpu(&m_cpu);
|
||||
|
||||
m_refreshDebuggerTimer.setInterval(1000);
|
||||
connect(&m_refreshDebuggerTimer, &QTimer::timeout, this, &CpuWidget::refreshDebugger);
|
||||
m_refreshDebuggerTimer.start();
|
||||
}
|
||||
|
||||
CpuWidget::~CpuWidget() = default;
|
||||
|
||||
void CpuWidget::setupSymbolTrees()
|
||||
{
|
||||
m_ui.tabFunctions->setLayout(new QVBoxLayout());
|
||||
m_ui.tabGlobalVariables->setLayout(new QVBoxLayout());
|
||||
m_ui.tabLocalVariables->setLayout(new QVBoxLayout());
|
||||
m_ui.tabParameterVariables->setLayout(new QVBoxLayout());
|
||||
|
||||
m_ui.tabFunctions->layout()->setContentsMargins(0, 0, 0, 0);
|
||||
m_ui.tabGlobalVariables->layout()->setContentsMargins(0, 0, 0, 0);
|
||||
m_ui.tabLocalVariables->layout()->setContentsMargins(0, 0, 0, 0);
|
||||
m_ui.tabParameterVariables->layout()->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
m_function_tree = new FunctionTreeWidget(m_cpu);
|
||||
m_global_variable_tree = new GlobalVariableTreeWidget(m_cpu);
|
||||
m_local_variable_tree = new LocalVariableTreeWidget(m_cpu);
|
||||
m_parameter_variable_tree = new ParameterVariableTreeWidget(m_cpu);
|
||||
|
||||
m_function_tree->updateModel();
|
||||
m_global_variable_tree->updateModel();
|
||||
m_local_variable_tree->updateModel();
|
||||
m_parameter_variable_tree->updateModel();
|
||||
|
||||
m_ui.tabFunctions->layout()->addWidget(m_function_tree);
|
||||
m_ui.tabGlobalVariables->layout()->addWidget(m_global_variable_tree);
|
||||
m_ui.tabLocalVariables->layout()->addWidget(m_local_variable_tree);
|
||||
m_ui.tabParameterVariables->layout()->addWidget(m_parameter_variable_tree);
|
||||
|
||||
connect(m_function_tree, &SymbolTreeWidget::goToInDisassembly, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddressAndSetFocus);
|
||||
connect(m_global_variable_tree, &SymbolTreeWidget::goToInDisassembly, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddressAndSetFocus);
|
||||
connect(m_local_variable_tree, &SymbolTreeWidget::goToInDisassembly, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddressAndSetFocus);
|
||||
connect(m_parameter_variable_tree, &SymbolTreeWidget::goToInDisassembly, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddressAndSetFocus);
|
||||
|
||||
connect(m_function_tree, &SymbolTreeWidget::goToInMemoryView, this, &CpuWidget::onGotoInMemory);
|
||||
connect(m_global_variable_tree, &SymbolTreeWidget::goToInMemoryView, this, &CpuWidget::onGotoInMemory);
|
||||
connect(m_local_variable_tree, &SymbolTreeWidget::goToInMemoryView, this, &CpuWidget::onGotoInMemory);
|
||||
connect(m_parameter_variable_tree, &SymbolTreeWidget::goToInMemoryView, this, &CpuWidget::onGotoInMemory);
|
||||
|
||||
connect(m_function_tree, &SymbolTreeWidget::nameColumnClicked, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddressAndSetFocus);
|
||||
connect(m_function_tree, &SymbolTreeWidget::locationColumnClicked, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddressAndSetFocus);
|
||||
}
|
||||
|
||||
void CpuWidget::refreshDebugger()
|
||||
{
|
||||
if (!m_cpu.isAlive())
|
||||
return;
|
||||
|
||||
m_ui.registerWidget->update();
|
||||
m_ui.disassemblyWidget->update();
|
||||
m_ui.memoryviewWidget->update();
|
||||
m_ui.memorySearchWidget->update();
|
||||
|
||||
m_function_tree->updateModel();
|
||||
m_global_variable_tree->updateModel();
|
||||
m_local_variable_tree->updateModel();
|
||||
m_parameter_variable_tree->updateModel();
|
||||
}
|
||||
|
||||
void CpuWidget::reloadCPUWidgets()
|
||||
{
|
||||
updateThreads();
|
||||
updateStackFrames();
|
||||
|
||||
m_ui.registerWidget->update();
|
||||
m_ui.disassemblyWidget->update();
|
||||
m_ui.memoryviewWidget->update();
|
||||
|
||||
m_function_tree->updateModel();
|
||||
m_global_variable_tree->updateModel();
|
||||
m_local_variable_tree->updateModel();
|
||||
m_parameter_variable_tree->updateModel();
|
||||
}
|
||||
|
||||
void CpuWidget::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
m_ui.registerWidget->update();
|
||||
m_ui.disassemblyWidget->update();
|
||||
m_ui.memoryviewWidget->update();
|
||||
m_ui.memorySearchWidget->update();
|
||||
}
|
||||
|
||||
// The cpu shouldn't be alive when these are called
|
||||
// But make sure it isn't just in case
|
||||
void CpuWidget::onStepInto()
|
||||
{
|
||||
if (!m_cpu.isAlive() || !m_cpu.isCpuPaused())
|
||||
return;
|
||||
|
||||
// Allow the cpu to skip this pc if it is a breakpoint
|
||||
CBreakPoints::SetSkipFirst(m_cpu.getCpuType(), m_cpu.getPC());
|
||||
|
||||
const u32 pc = m_cpu.getPC();
|
||||
const MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(&m_cpu, pc);
|
||||
|
||||
u32 bpAddr = pc + 0x4; // Default to the next instruction
|
||||
|
||||
if (info.isBranch)
|
||||
{
|
||||
if (!info.isConditional)
|
||||
{
|
||||
bpAddr = info.branchTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info.conditionMet)
|
||||
{
|
||||
bpAddr = info.branchTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
bpAddr = pc + (2 * 4); // Skip branch delay slot
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info.isSyscall)
|
||||
bpAddr = info.branchTarget; // Syscalls are always taken
|
||||
|
||||
Host::RunOnCPUThread([cpu = &m_cpu, bpAddr] {
|
||||
CBreakPoints::AddBreakPoint(cpu->getCpuType(), bpAddr, true);
|
||||
cpu->resumeCpu();
|
||||
});
|
||||
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void CpuWidget::onStepOut()
|
||||
{
|
||||
if (!m_cpu.isAlive() || !m_cpu.isCpuPaused())
|
||||
return;
|
||||
|
||||
// Allow the cpu to skip this pc if it is a breakpoint
|
||||
CBreakPoints::SetSkipFirst(m_cpu.getCpuType(), m_cpu.getPC());
|
||||
|
||||
if (m_stackModel.rowCount() < 2)
|
||||
return;
|
||||
|
||||
Host::RunOnCPUThread([cpu = &m_cpu, stackModel = &m_stackModel] {
|
||||
CBreakPoints::AddBreakPoint(cpu->getCpuType(), stackModel->data(stackModel->index(1, StackModel::PC), Qt::UserRole).toUInt(), true);
|
||||
cpu->resumeCpu();
|
||||
});
|
||||
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void CpuWidget::onStepOver()
|
||||
{
|
||||
if (!m_cpu.isAlive() || !m_cpu.isCpuPaused())
|
||||
return;
|
||||
|
||||
const u32 pc = m_cpu.getPC();
|
||||
const MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(&m_cpu, pc);
|
||||
|
||||
u32 bpAddr = pc + 0x4; // Default to the next instruction
|
||||
|
||||
if (info.isBranch)
|
||||
{
|
||||
if (!info.isConditional)
|
||||
{
|
||||
if (info.isLinkedBranch) // jal, jalr
|
||||
{
|
||||
// it's a function call with a delay slot - skip that too
|
||||
bpAddr += 4;
|
||||
}
|
||||
else // j, ...
|
||||
{
|
||||
// in case of absolute branches, set the breakpoint at the branch target
|
||||
bpAddr = info.branchTarget;
|
||||
}
|
||||
}
|
||||
else // beq, ...
|
||||
{
|
||||
if (info.conditionMet)
|
||||
{
|
||||
bpAddr = info.branchTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
bpAddr = pc + (2 * 4); // Skip branch delay slot
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Host::RunOnCPUThread([cpu = &m_cpu, bpAddr] {
|
||||
CBreakPoints::AddBreakPoint(cpu->getCpuType(), bpAddr, true);
|
||||
cpu->resumeCpu();
|
||||
});
|
||||
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void CpuWidget::onVMPaused()
|
||||
{
|
||||
// Stops us from telling the disassembly dialog to jump somwhere because breakpoint code paused the core.
|
||||
if (CBreakPoints::GetCorePaused())
|
||||
{
|
||||
CBreakPoints::SetCorePaused(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.disassemblyWidget->gotoProgramCounterOnPause();
|
||||
}
|
||||
|
||||
reloadCPUWidgets();
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void CpuWidget::updateBreakpoints()
|
||||
{
|
||||
m_bpModel.refreshData();
|
||||
}
|
||||
|
||||
void CpuWidget::onBPListDoubleClicked(const QModelIndex& index)
|
||||
{
|
||||
if (index.isValid())
|
||||
{
|
||||
if (index.column() == BreakpointModel::OFFSET)
|
||||
{
|
||||
m_ui.disassemblyWidget->gotoAddressAndSetFocus(m_bpModel.data(index, BreakpointModel::DataRole).toUInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CpuWidget::onBPListContextMenu(QPoint pos)
|
||||
{
|
||||
QMenu* contextMenu = new QMenu(tr("Breakpoint List Context Menu"), m_ui.breakpointList);
|
||||
if (m_cpu.isAlive())
|
||||
{
|
||||
|
||||
QAction* newAction = new QAction(tr("New"), m_ui.breakpointList);
|
||||
connect(newAction, &QAction::triggered, this, &CpuWidget::contextBPListNew);
|
||||
contextMenu->addAction(newAction);
|
||||
|
||||
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
|
||||
|
||||
if (selModel->hasSelection())
|
||||
{
|
||||
QAction* editAction = new QAction(tr("Edit"), m_ui.breakpointList);
|
||||
connect(editAction, &QAction::triggered, this, &CpuWidget::contextBPListEdit);
|
||||
contextMenu->addAction(editAction);
|
||||
|
||||
if (selModel->selectedIndexes().count() == 1)
|
||||
{
|
||||
QAction* copyAction = new QAction(tr("Copy"), m_ui.breakpointList);
|
||||
connect(copyAction, &QAction::triggered, this, &CpuWidget::contextBPListCopy);
|
||||
contextMenu->addAction(copyAction);
|
||||
}
|
||||
|
||||
QAction* deleteAction = new QAction(tr("Delete"), m_ui.breakpointList);
|
||||
connect(deleteAction, &QAction::triggered, this, &CpuWidget::contextBPListDelete);
|
||||
contextMenu->addAction(deleteAction);
|
||||
}
|
||||
}
|
||||
|
||||
contextMenu->addSeparator();
|
||||
if (m_bpModel.rowCount() > 0)
|
||||
{
|
||||
QAction* actionExport = new QAction(tr("Copy all as CSV"), m_ui.breakpointList);
|
||||
connect(actionExport, &QAction::triggered, [this]() {
|
||||
// It's important to use the Export Role here to allow pasting to be translation agnostic
|
||||
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.breakpointList->model(), BreakpointModel::ExportRole, true));
|
||||
});
|
||||
contextMenu->addAction(actionExport);
|
||||
}
|
||||
|
||||
if (m_cpu.isAlive())
|
||||
{
|
||||
QAction* actionImport = new QAction(tr("Paste from CSV"), m_ui.breakpointList);
|
||||
connect(actionImport, &QAction::triggered, this, &CpuWidget::contextBPListPasteCSV);
|
||||
contextMenu->addAction(actionImport);
|
||||
|
||||
QAction* actionLoad = new QAction(tr("Load from Settings"), m_ui.breakpointList);
|
||||
connect(actionLoad, &QAction::triggered, [this]() {
|
||||
m_bpModel.clear();
|
||||
DebuggerSettingsManager::loadGameSettings(&m_bpModel);
|
||||
});
|
||||
contextMenu->addAction(actionLoad);
|
||||
|
||||
QAction* actionSave = new QAction(tr("Save to Settings"), m_ui.breakpointList);
|
||||
connect(actionSave, &QAction::triggered, this, &CpuWidget::saveBreakpointsToDebuggerSettings);
|
||||
contextMenu->addAction(actionSave);
|
||||
}
|
||||
|
||||
contextMenu->popup(m_ui.breakpointList->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void CpuWidget::onGotoInMemory(u32 address)
|
||||
{
|
||||
m_ui.memoryviewWidget->gotoAddress(address);
|
||||
m_ui.tabWidget->setCurrentWidget(m_ui.tab_memory);
|
||||
}
|
||||
|
||||
void CpuWidget::contextBPListCopy()
|
||||
{
|
||||
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
|
||||
|
||||
if (!selModel->hasSelection())
|
||||
return;
|
||||
|
||||
QGuiApplication::clipboard()->setText(m_bpModel.data(selModel->currentIndex()).toString());
|
||||
}
|
||||
|
||||
void CpuWidget::contextBPListDelete()
|
||||
{
|
||||
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
|
||||
|
||||
if (!selModel->hasSelection())
|
||||
return;
|
||||
|
||||
QModelIndexList rows = selModel->selectedIndexes();
|
||||
|
||||
std::sort(rows.begin(), rows.end(), [](const QModelIndex& a, const QModelIndex& b) {
|
||||
return a.row() > b.row();
|
||||
});
|
||||
|
||||
for (const QModelIndex& index : rows)
|
||||
{
|
||||
m_bpModel.removeRows(index.row(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuWidget::contextBPListNew()
|
||||
{
|
||||
BreakpointDialog* bpDialog = new BreakpointDialog(this, &m_cpu, m_bpModel);
|
||||
bpDialog->show();
|
||||
}
|
||||
|
||||
void CpuWidget::contextBPListEdit()
|
||||
{
|
||||
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
|
||||
|
||||
if (!selModel->hasSelection())
|
||||
return;
|
||||
|
||||
const int selectedRow = selModel->selectedIndexes().first().row();
|
||||
|
||||
auto bpObject = m_bpModel.at(selectedRow);
|
||||
|
||||
BreakpointDialog* bpDialog = new BreakpointDialog(this, &m_cpu, m_bpModel, bpObject, selectedRow);
|
||||
bpDialog->show();
|
||||
}
|
||||
|
||||
void CpuWidget::contextBPListPasteCSV()
|
||||
{
|
||||
QString csv = QGuiApplication::clipboard()->text();
|
||||
// Skip header
|
||||
csv = csv.mid(csv.indexOf('\n') + 1);
|
||||
|
||||
for (const QString& line : csv.split('\n'))
|
||||
{
|
||||
QStringList fields;
|
||||
// In order to handle text with commas in them we must wrap values in quotes to mark
|
||||
// where a value starts and end so that text commas aren't identified as delimiters.
|
||||
// So matches each quote pair, parse it out, and removes the quotes to get the value.
|
||||
QRegularExpression eachQuotePair(R"("([^"]|\\.)*")");
|
||||
QRegularExpressionMatchIterator it = eachQuotePair.globalMatch(line);
|
||||
while (it.hasNext())
|
||||
{
|
||||
QRegularExpressionMatch match = it.next();
|
||||
QString matchedValue = match.captured(0);
|
||||
fields << matchedValue.mid(1, matchedValue.length() - 2);
|
||||
}
|
||||
m_bpModel.loadBreakpointFromFieldList(fields);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuWidget::onSavedAddressesListContextMenu(QPoint pos)
|
||||
{
|
||||
QMenu* contextMenu = new QMenu("Saved Addresses List Context Menu", m_ui.savedAddressesList);
|
||||
|
||||
QAction* newAction = new QAction(tr("New"), m_ui.savedAddressesList);
|
||||
connect(newAction, &QAction::triggered, this, &CpuWidget::contextSavedAddressesListNew);
|
||||
contextMenu->addAction(newAction);
|
||||
|
||||
const QModelIndex indexAtPos = m_ui.savedAddressesList->indexAt(pos);
|
||||
const bool isIndexValid = indexAtPos.isValid();
|
||||
|
||||
if (isIndexValid)
|
||||
{
|
||||
if (m_cpu.isAlive())
|
||||
{
|
||||
QAction* goToAddressMemViewAction = new QAction(tr("Go to in Memory View"), m_ui.savedAddressesList);
|
||||
connect(goToAddressMemViewAction, &QAction::triggered, this, [this, indexAtPos]() {
|
||||
const QModelIndex rowAddressIndex = m_ui.savedAddressesList->model()->index(indexAtPos.row(), 0, QModelIndex());
|
||||
m_ui.memoryviewWidget->gotoAddress(m_ui.savedAddressesList->model()->data(rowAddressIndex, Qt::UserRole).toUInt());
|
||||
m_ui.tabWidget->setCurrentWidget(m_ui.tab_memory);
|
||||
});
|
||||
contextMenu->addAction(goToAddressMemViewAction);
|
||||
|
||||
QAction* goToAddressDisassemblyAction = new QAction(tr("Go to in Disassembly"), m_ui.savedAddressesList);
|
||||
connect(goToAddressDisassemblyAction, &QAction::triggered, this, [this, indexAtPos]() {
|
||||
const QModelIndex rowAddressIndex = m_ui.savedAddressesList->model()->index(indexAtPos.row(), 0, QModelIndex());
|
||||
m_ui.disassemblyWidget->gotoAddressAndSetFocus(m_ui.savedAddressesList->model()->data(rowAddressIndex, Qt::UserRole).toUInt());
|
||||
});
|
||||
contextMenu->addAction(goToAddressDisassemblyAction);
|
||||
}
|
||||
|
||||
QAction* copyAction = new QAction(indexAtPos.column() == 0 ? tr("Copy Address") : tr("Copy Text"), m_ui.savedAddressesList);
|
||||
connect(copyAction, &QAction::triggered, [this, indexAtPos]() {
|
||||
QGuiApplication::clipboard()->setText(m_ui.savedAddressesList->model()->data(indexAtPos, Qt::DisplayRole).toString());
|
||||
});
|
||||
contextMenu->addAction(copyAction);
|
||||
}
|
||||
|
||||
if (m_ui.savedAddressesList->model()->rowCount() > 0)
|
||||
{
|
||||
QAction* actionExportCSV = new QAction(tr("Copy all as CSV"), m_ui.savedAddressesList);
|
||||
connect(actionExportCSV, &QAction::triggered, [this]() {
|
||||
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.savedAddressesList->model(), Qt::DisplayRole, true));
|
||||
});
|
||||
contextMenu->addAction(actionExportCSV);
|
||||
}
|
||||
|
||||
QAction* actionImportCSV = new QAction(tr("Paste from CSV"), m_ui.savedAddressesList);
|
||||
connect(actionImportCSV, &QAction::triggered, this, &CpuWidget::contextSavedAddressesListPasteCSV);
|
||||
contextMenu->addAction(actionImportCSV);
|
||||
|
||||
if (m_cpu.isAlive())
|
||||
{
|
||||
QAction* actionLoad = new QAction(tr("Load from Settings"), m_ui.savedAddressesList);
|
||||
connect(actionLoad, &QAction::triggered, [this]() {
|
||||
m_savedAddressesModel.clear();
|
||||
DebuggerSettingsManager::loadGameSettings(&m_savedAddressesModel);
|
||||
});
|
||||
contextMenu->addAction(actionLoad);
|
||||
|
||||
QAction* actionSave = new QAction(tr("Save to Settings"), m_ui.savedAddressesList);
|
||||
connect(actionSave, &QAction::triggered, this, &CpuWidget::saveSavedAddressesToDebuggerSettings);
|
||||
contextMenu->addAction(actionSave);
|
||||
}
|
||||
|
||||
if (isIndexValid)
|
||||
{
|
||||
QAction* deleteAction = new QAction(tr("Delete"), m_ui.savedAddressesList);
|
||||
connect(deleteAction, &QAction::triggered, this, [this, indexAtPos]() {
|
||||
m_ui.savedAddressesList->model()->removeRows(indexAtPos.row(), 1);
|
||||
});
|
||||
contextMenu->addAction(deleteAction);
|
||||
}
|
||||
|
||||
contextMenu->popup(m_ui.savedAddressesList->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void CpuWidget::contextSavedAddressesListPasteCSV()
|
||||
{
|
||||
QString csv = QGuiApplication::clipboard()->text();
|
||||
// Skip header
|
||||
csv = csv.mid(csv.indexOf('\n') + 1);
|
||||
|
||||
for (const QString& line : csv.split('\n'))
|
||||
{
|
||||
QStringList fields;
|
||||
// In order to handle text with commas in them we must wrap values in quotes to mark
|
||||
// where a value starts and end so that text commas aren't identified as delimiters.
|
||||
// So matches each quote pair, parse it out, and removes the quotes to get the value.
|
||||
QRegularExpression eachQuotePair(R"("([^"]|\\.)*")");
|
||||
QRegularExpressionMatchIterator it = eachQuotePair.globalMatch(line);
|
||||
while (it.hasNext())
|
||||
{
|
||||
QRegularExpressionMatch match = it.next();
|
||||
QString matchedValue = match.captured(0);
|
||||
fields << matchedValue.mid(1, matchedValue.length() - 2);
|
||||
}
|
||||
|
||||
m_savedAddressesModel.loadSavedAddressFromFieldList(fields);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuWidget::contextSavedAddressesListNew()
|
||||
{
|
||||
qobject_cast<SavedAddressesModel*>(m_ui.savedAddressesList->model())->addRow();
|
||||
const u32 rowCount = m_ui.savedAddressesList->model()->rowCount();
|
||||
m_ui.savedAddressesList->edit(m_ui.savedAddressesList->model()->index(rowCount - 1, 0));
|
||||
}
|
||||
|
||||
void CpuWidget::addAddressToSavedAddressesList(u32 address)
|
||||
{
|
||||
qobject_cast<SavedAddressesModel*>(m_ui.savedAddressesList->model())->addRow();
|
||||
const u32 rowCount = m_ui.savedAddressesList->model()->rowCount();
|
||||
const QModelIndex addressIndex = m_ui.savedAddressesList->model()->index(rowCount - 1, 0);
|
||||
m_ui.tabWidget->setCurrentWidget(m_ui.tab_savedaddresses);
|
||||
m_ui.savedAddressesList->model()->setData(addressIndex, address, Qt::UserRole);
|
||||
m_ui.savedAddressesList->edit(m_ui.savedAddressesList->model()->index(rowCount - 1, 1));
|
||||
}
|
||||
|
||||
void CpuWidget::updateThreads()
|
||||
{
|
||||
m_threadModel.refreshData();
|
||||
}
|
||||
|
||||
void CpuWidget::onThreadListContextMenu(QPoint pos)
|
||||
{
|
||||
if (!m_ui.threadList->selectionModel()->hasSelection())
|
||||
return;
|
||||
|
||||
QMenu* contextMenu = new QMenu(tr("Thread List Context Menu"), m_ui.threadList);
|
||||
|
||||
QAction* actionCopy = new QAction(tr("Copy"), m_ui.threadList);
|
||||
connect(actionCopy, &QAction::triggered, [this]() {
|
||||
const auto* selModel = m_ui.threadList->selectionModel();
|
||||
|
||||
if (!selModel->hasSelection())
|
||||
return;
|
||||
|
||||
QGuiApplication::clipboard()->setText(m_ui.threadList->model()->data(selModel->currentIndex()).toString());
|
||||
});
|
||||
contextMenu->addAction(actionCopy);
|
||||
|
||||
contextMenu->addSeparator();
|
||||
|
||||
QAction* actionExport = new QAction(tr("Copy all as CSV"), m_ui.threadList);
|
||||
connect(actionExport, &QAction::triggered, [this]() {
|
||||
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.threadList->model()));
|
||||
});
|
||||
contextMenu->addAction(actionExport);
|
||||
|
||||
contextMenu->popup(m_ui.threadList->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void CpuWidget::onThreadListDoubleClick(const QModelIndex& index)
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case ThreadModel::ThreadColumns::ENTRY:
|
||||
m_ui.memoryviewWidget->gotoAddress(m_ui.threadList->model()->data(index, Qt::UserRole).toUInt());
|
||||
m_ui.tabWidget->setCurrentWidget(m_ui.tab_memory);
|
||||
break;
|
||||
default: // Default to PC
|
||||
m_ui.disassemblyWidget->gotoAddressAndSetFocus(m_ui.threadList->model()->data(m_ui.threadList->model()->index(index.row(), ThreadModel::ThreadColumns::PC), Qt::UserRole).toUInt());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CpuWidget::updateStackFrames()
|
||||
{
|
||||
m_stackModel.refreshData();
|
||||
}
|
||||
|
||||
void CpuWidget::onStackListContextMenu(QPoint pos)
|
||||
{
|
||||
if (!m_ui.stackList->selectionModel()->hasSelection())
|
||||
return;
|
||||
|
||||
QMenu* contextMenu = new QMenu(tr("Stack List Context Menu"), m_ui.stackList);
|
||||
|
||||
QAction* actionCopy = new QAction(tr("Copy"), m_ui.stackList);
|
||||
connect(actionCopy, &QAction::triggered, [this]() {
|
||||
const auto* selModel = m_ui.stackList->selectionModel();
|
||||
|
||||
if (!selModel->hasSelection())
|
||||
return;
|
||||
|
||||
QGuiApplication::clipboard()->setText(m_ui.stackList->model()->data(selModel->currentIndex()).toString());
|
||||
});
|
||||
contextMenu->addAction(actionCopy);
|
||||
|
||||
contextMenu->addSeparator();
|
||||
|
||||
QAction* actionExport = new QAction(tr("Copy all as CSV"), m_ui.stackList);
|
||||
connect(actionExport, &QAction::triggered, [this]() {
|
||||
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.stackList->model()));
|
||||
});
|
||||
contextMenu->addAction(actionExport);
|
||||
|
||||
contextMenu->popup(m_ui.stackList->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void CpuWidget::onStackListDoubleClick(const QModelIndex& index)
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case StackModel::StackModel::ENTRY:
|
||||
case StackModel::StackModel::ENTRY_LABEL:
|
||||
m_ui.disassemblyWidget->gotoAddressAndSetFocus(m_ui.stackList->model()->data(m_ui.stackList->model()->index(index.row(), StackModel::StackColumns::ENTRY), Qt::UserRole).toUInt());
|
||||
break;
|
||||
case StackModel::StackModel::SP:
|
||||
m_ui.memoryviewWidget->gotoAddress(m_ui.stackList->model()->data(index, Qt::UserRole).toUInt());
|
||||
m_ui.tabWidget->setCurrentWidget(m_ui.tab_memory);
|
||||
break;
|
||||
default: // Default to PC
|
||||
m_ui.disassemblyWidget->gotoAddressAndSetFocus(m_ui.stackList->model()->data(m_ui.stackList->model()->index(index.row(), StackModel::StackColumns::PC), Qt::UserRole).toUInt());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CpuWidget::saveBreakpointsToDebuggerSettings()
|
||||
{
|
||||
DebuggerSettingsManager::saveGameSettings(&m_bpModel);
|
||||
}
|
||||
|
||||
void CpuWidget::saveSavedAddressesToDebuggerSettings()
|
||||
{
|
||||
DebuggerSettingsManager::saveGameSettings(&m_savedAddressesModel);
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_CpuWidget.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
#include "Models/BreakpointModel.h"
|
||||
#include "Models/ThreadModel.h"
|
||||
#include "Models/StackModel.h"
|
||||
#include "Models/SavedAddressesModel.h"
|
||||
#include "Debugger/SymbolTree/SymbolTreeWidgets.h"
|
||||
|
||||
#include "QtHost.h"
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <QtWidgets/QTableWidget>
|
||||
#include <QtCore/QSortFilterProxyModel>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace MipsStackWalk;
|
||||
|
||||
class CpuWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CpuWidget(QWidget* parent, DebugInterface& cpu);
|
||||
~CpuWidget();
|
||||
|
||||
public slots:
|
||||
void paintEvent(QPaintEvent* event);
|
||||
|
||||
void onStepInto();
|
||||
void onStepOver();
|
||||
void onStepOut();
|
||||
|
||||
void onVMPaused();
|
||||
|
||||
void updateBreakpoints();
|
||||
void onBPListDoubleClicked(const QModelIndex& index);
|
||||
void onBPListContextMenu(QPoint pos);
|
||||
void onGotoInMemory(u32 address);
|
||||
|
||||
void contextBPListCopy();
|
||||
void contextBPListDelete();
|
||||
void contextBPListNew();
|
||||
void contextBPListEdit();
|
||||
void contextBPListPasteCSV();
|
||||
|
||||
void onSavedAddressesListContextMenu(QPoint pos);
|
||||
void contextSavedAddressesListPasteCSV();
|
||||
void contextSavedAddressesListNew();
|
||||
void addAddressToSavedAddressesList(u32 address);
|
||||
|
||||
void updateThreads();
|
||||
void onThreadListDoubleClick(const QModelIndex& index);
|
||||
void onThreadListContextMenu(QPoint pos);
|
||||
|
||||
void updateStackFrames();
|
||||
void onStackListContextMenu(QPoint pos);
|
||||
void onStackListDoubleClick(const QModelIndex& index);
|
||||
|
||||
void refreshDebugger();
|
||||
void reloadCPUWidgets();
|
||||
|
||||
void saveBreakpointsToDebuggerSettings();
|
||||
void saveSavedAddressesToDebuggerSettings();
|
||||
|
||||
private:
|
||||
void setupSymbolTrees();
|
||||
|
||||
std::vector<QTableWidget*> m_registerTableViews;
|
||||
|
||||
QMenu* m_stacklistContextMenu = 0;
|
||||
QMenu* m_funclistContextMenu = 0;
|
||||
QMenu* m_moduleTreeContextMenu = 0;
|
||||
QTimer m_refreshDebuggerTimer;
|
||||
|
||||
Ui::CpuWidget m_ui;
|
||||
|
||||
DebugInterface& m_cpu;
|
||||
|
||||
BreakpointModel m_bpModel;
|
||||
ThreadModel m_threadModel;
|
||||
QSortFilterProxyModel m_threadProxyModel;
|
||||
StackModel m_stackModel;
|
||||
SavedAddressesModel m_savedAddressesModel;
|
||||
|
||||
FunctionTreeWidget* m_function_tree = nullptr;
|
||||
GlobalVariableTreeWidget* m_global_variable_tree = nullptr;
|
||||
LocalVariableTreeWidget* m_local_variable_tree = nullptr;
|
||||
ParameterVariableTreeWidget* m_parameter_variable_tree = nullptr;
|
||||
};
|
||||
@@ -1,445 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CpuWidget</class>
|
||||
<widget class="QWidget" name="CpuWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>668</width>
|
||||
<height>563</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QSplitter" name="verticalSplitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="childrenCollapsible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QSplitter" name="horizontalSplitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="childrenCollapsible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QTabWidget" name="tabWidgetRegFunc">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabRegisters">
|
||||
<attribute name="title">
|
||||
<string>Registers</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="registerLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="RegisterWidget" name="registerWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabFunctions">
|
||||
<attribute name="title">
|
||||
<string>Functions</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabMemorySearch">
|
||||
<attribute name="title">
|
||||
<string>Memory Search</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="memorySearchLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="MemorySearchWidget" name="memorySearchWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="DisassemblyWidget" name="disassemblyWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="tabPosition">
|
||||
<enum>QTabWidget::North</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_memory">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Memory</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="memoryLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="MemoryViewWidget" name="memoryviewWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_breakpoints">
|
||||
<attribute name="title">
|
||||
<string>Breakpoints</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="breakpointsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableView" name="breakpointList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="gridStyle">
|
||||
<enum>Qt::NoPen</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_threads">
|
||||
<attribute name="title">
|
||||
<string>Threads</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="threadsLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableView" name="threadList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="gridStyle">
|
||||
<enum>Qt::NoPen</enum>
|
||||
</property>
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_callstack">
|
||||
<attribute name="title">
|
||||
<string>Active Call Stack</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="callStackLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableView" name="stackList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="gridStyle">
|
||||
<enum>Qt::NoPen</enum>
|
||||
</property>
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_savedaddresses">
|
||||
<attribute name="title">
|
||||
<string>Saved Addresses</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="savedAddressesLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableView" name="savedAddressesList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="gridStyle">
|
||||
<enum>Qt::NoPen</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabGlobalVariables">
|
||||
<attribute name="title">
|
||||
<string>Globals</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabLocalVariables">
|
||||
<attribute name="title">
|
||||
<string>Locals</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabParameterVariables">
|
||||
<attribute name="title">
|
||||
<string>Parameters</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>DisassemblyWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>pcsx2-qt/Debugger/DisassemblyWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>RegisterWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>pcsx2-qt/Debugger/RegisterWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MemoryViewWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>pcsx2-qt/Debugger/MemoryViewWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MemorySearchWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>pcsx2-qt/Debugger/MemorySearchWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
58
pcsx2-qt/Debugger/DebuggerEvents.h
Normal file
58
pcsx2-qt/Debugger/DebuggerEvents.h
Normal file
@@ -0,0 +1,58 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/Pcsx2Types.h>
|
||||
|
||||
#include <QtCore/qttranslation.h>
|
||||
|
||||
namespace DebuggerEvents
|
||||
{
|
||||
struct Event
|
||||
{
|
||||
virtual ~Event() = default;
|
||||
};
|
||||
|
||||
// Sent when a debugger widget is first created, and subsequently broadcast
|
||||
// to all debugger widgets at regular intervals.
|
||||
struct Refresh : Event
|
||||
{
|
||||
};
|
||||
|
||||
// Go to the address in a disassembly or memory view and switch to that tab.
|
||||
struct GoToAddress : Event
|
||||
{
|
||||
enum Filter
|
||||
{
|
||||
NONE,
|
||||
DISASSEMBLER,
|
||||
MEMORY_VIEW
|
||||
};
|
||||
|
||||
u32 address = 0;
|
||||
|
||||
// Prevent the memory view from handling events for jumping to functions
|
||||
// and vice versa.
|
||||
Filter filter = NONE;
|
||||
|
||||
bool switch_to_tab = true;
|
||||
|
||||
static constexpr const char* ACTION_PREFIX = QT_TRANSLATE_NOOP("DebuggerEvents", "Go to in");
|
||||
};
|
||||
|
||||
// The state of the VM has changed and widgets should be updated to reflect
|
||||
// the new state (e.g. the VM has been paused).
|
||||
struct VMUpdate : Event
|
||||
{
|
||||
};
|
||||
|
||||
// Add the address to the saved addresses list and switch to that tab.
|
||||
struct AddToSavedAddresses : Event
|
||||
{
|
||||
u32 address = 0;
|
||||
bool switch_to_tab = true;
|
||||
|
||||
static constexpr const char* ACTION_PREFIX = QT_TRANSLATE_NOOP("DebuggerEvents", "Add to");
|
||||
};
|
||||
} // namespace DebuggerEvents
|
||||
@@ -10,12 +10,12 @@
|
||||
|
||||
#include "common/Console.h"
|
||||
#include "VMManager.h"
|
||||
#include "Models/BreakpointModel.h"
|
||||
|
||||
std::mutex DebuggerSettingsManager::writeLock;
|
||||
const QString DebuggerSettingsManager::settingsFileVersion = "0.00";
|
||||
|
||||
QJsonObject DebuggerSettingsManager::loadGameSettingsJSON() {
|
||||
QJsonObject DebuggerSettingsManager::loadGameSettingsJSON()
|
||||
{
|
||||
std::string path = VMManager::GetDebuggerSettingsFilePathForCurrentGame();
|
||||
QFile file(QString::fromStdString(path));
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
@@ -134,7 +134,7 @@ void DebuggerSettingsManager::saveGameSettings(QAbstractTableModel* abstractTabl
|
||||
{
|
||||
const std::string path = VMManager::GetDebuggerSettingsFilePathForCurrentGame();
|
||||
if (path.empty())
|
||||
return;
|
||||
return;
|
||||
|
||||
const std::lock_guard<std::mutex> lock(writeLock);
|
||||
QJsonObject loadedSettings = loadGameSettingsJSON();
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "Models/BreakpointModel.h"
|
||||
#include "Models/SavedAddressesModel.h"
|
||||
#include "Breakpoints/BreakpointModel.h"
|
||||
#include "Memory/SavedAddressesModel.h"
|
||||
|
||||
class DebuggerSettingsManager final
|
||||
{
|
||||
|
||||
312
pcsx2-qt/Debugger/DebuggerWidget.cpp
Normal file
312
pcsx2-qt/Debugger/DebuggerWidget.cpp
Normal file
@@ -0,0 +1,312 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "DebuggerWidget.h"
|
||||
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
#include "Debugger/JsonValueWrapper.h"
|
||||
#include "Debugger/Docking/DockManager.h"
|
||||
#include "Debugger/Docking/DockTables.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
|
||||
DebuggerWidget::DebuggerWidget(const DebuggerWidgetParameters& parameters, u32 flags)
|
||||
: QWidget(parameters.parent)
|
||||
, m_unique_name(parameters.unique_name)
|
||||
, m_cpu(parameters.cpu)
|
||||
, m_cpu_override(parameters.cpu_override)
|
||||
, m_flags(flags)
|
||||
{
|
||||
updateStyleSheet();
|
||||
}
|
||||
|
||||
DebugInterface& DebuggerWidget::cpu() const
|
||||
{
|
||||
if (m_cpu_override.has_value())
|
||||
return DebugInterface::get(*m_cpu_override);
|
||||
|
||||
pxAssertRel(m_cpu, "DebuggerWidget::cpu called on object with null cpu.");
|
||||
return *m_cpu;
|
||||
}
|
||||
|
||||
QString DebuggerWidget::uniqueName() const
|
||||
{
|
||||
return m_unique_name;
|
||||
}
|
||||
|
||||
QString DebuggerWidget::displayName() const
|
||||
{
|
||||
QString name = displayNameWithoutSuffix();
|
||||
|
||||
// If there are multiple debugger widgets of the same name, append a number
|
||||
// to the display name.
|
||||
if (m_display_name_suffix_number.has_value())
|
||||
name = tr("%1 #%2").arg(name).arg(*m_display_name_suffix_number);
|
||||
|
||||
if (m_cpu_override)
|
||||
name = tr("%1 (%2)").arg(name).arg(DebugInterface::cpuName(*m_cpu_override));
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
QString DebuggerWidget::displayNameWithoutSuffix() const
|
||||
{
|
||||
return m_translated_display_name;
|
||||
}
|
||||
|
||||
QString DebuggerWidget::customDisplayName() const
|
||||
{
|
||||
return m_custom_display_name;
|
||||
}
|
||||
|
||||
bool DebuggerWidget::setCustomDisplayName(QString display_name)
|
||||
{
|
||||
if (display_name.size() > DockUtils::MAX_DOCK_WIDGET_NAME_SIZE)
|
||||
return false;
|
||||
|
||||
m_custom_display_name = display_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebuggerWidget::isPrimary() const
|
||||
{
|
||||
return m_is_primary;
|
||||
}
|
||||
|
||||
void DebuggerWidget::setPrimary(bool is_primary)
|
||||
{
|
||||
m_is_primary = is_primary;
|
||||
}
|
||||
|
||||
bool DebuggerWidget::setCpu(DebugInterface& new_cpu)
|
||||
{
|
||||
BreakPointCpu before = cpu().getCpuType();
|
||||
m_cpu = &new_cpu;
|
||||
BreakPointCpu after = cpu().getCpuType();
|
||||
return before == after;
|
||||
}
|
||||
|
||||
std::optional<BreakPointCpu> DebuggerWidget::cpuOverride() const
|
||||
{
|
||||
return m_cpu_override;
|
||||
}
|
||||
|
||||
bool DebuggerWidget::setCpuOverride(std::optional<BreakPointCpu> new_cpu)
|
||||
{
|
||||
BreakPointCpu before = cpu().getCpuType();
|
||||
m_cpu_override = new_cpu;
|
||||
BreakPointCpu after = cpu().getCpuType();
|
||||
return before == after;
|
||||
}
|
||||
|
||||
bool DebuggerWidget::handleEvent(const DebuggerEvents::Event& event)
|
||||
{
|
||||
auto [begin, end] = m_event_handlers.equal_range(typeid(event).name());
|
||||
for (auto handler = begin; handler != end; handler++)
|
||||
if (handler->second(event))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DebuggerWidget::acceptsEventType(const char* event_type)
|
||||
{
|
||||
auto [begin, end] = m_event_handlers.equal_range(event_type);
|
||||
return begin != end;
|
||||
}
|
||||
|
||||
|
||||
void DebuggerWidget::toJson(JsonValueWrapper& json)
|
||||
{
|
||||
std::string custom_display_name_str = m_custom_display_name.toStdString();
|
||||
rapidjson::Value custom_display_name;
|
||||
custom_display_name.SetString(custom_display_name_str.c_str(), custom_display_name_str.size(), json.allocator());
|
||||
json.value().AddMember("customDisplayName", custom_display_name, json.allocator());
|
||||
|
||||
json.value().AddMember("isPrimary", m_is_primary, json.allocator());
|
||||
}
|
||||
|
||||
bool DebuggerWidget::fromJson(const JsonValueWrapper& json)
|
||||
{
|
||||
auto custom_display_name = json.value().FindMember("customDisplayName");
|
||||
if (custom_display_name != json.value().MemberEnd() && custom_display_name->value.IsString())
|
||||
{
|
||||
m_custom_display_name = QString(custom_display_name->value.GetString());
|
||||
m_custom_display_name.truncate(DockUtils::MAX_DOCK_WIDGET_NAME_SIZE);
|
||||
}
|
||||
|
||||
auto is_primary = json.value().FindMember("isPrimary");
|
||||
if (is_primary != json.value().MemberEnd() && is_primary->value.IsBool())
|
||||
m_is_primary = is_primary->value.GetBool();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DebuggerWidget::switchToThisTab()
|
||||
{
|
||||
g_debugger_window->dockManager().switchToDebuggerWidget(this);
|
||||
}
|
||||
|
||||
bool DebuggerWidget::supportsMultipleInstances()
|
||||
{
|
||||
return !(m_flags & DISALLOW_MULTIPLE_INSTANCES);
|
||||
}
|
||||
|
||||
void DebuggerWidget::retranslateDisplayName()
|
||||
{
|
||||
if (!m_custom_display_name.isEmpty())
|
||||
{
|
||||
m_translated_display_name = m_custom_display_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto description = DockTables::DEBUGGER_WIDGETS.find(metaObject()->className());
|
||||
if (description != DockTables::DEBUGGER_WIDGETS.end())
|
||||
m_translated_display_name = QCoreApplication::translate("DebuggerWidget", description->second.display_name);
|
||||
else
|
||||
m_translated_display_name = QString();
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<int> DebuggerWidget::displayNameSuffixNumber() const
|
||||
{
|
||||
return m_display_name_suffix_number;
|
||||
}
|
||||
|
||||
void DebuggerWidget::setDisplayNameSuffixNumber(std::optional<int> suffix_number)
|
||||
{
|
||||
m_display_name_suffix_number = suffix_number;
|
||||
}
|
||||
|
||||
void DebuggerWidget::updateStyleSheet()
|
||||
{
|
||||
QString stylesheet;
|
||||
|
||||
if (m_flags & MONOSPACE_FONT)
|
||||
{
|
||||
// Easiest way to handle cross platform monospace fonts
|
||||
// There are issues related to TabWidget -> Children font inheritance otherwise
|
||||
#if defined(WIN32)
|
||||
stylesheet += QStringLiteral("font-family: 'Lucida Console';");
|
||||
#elif defined(__APPLE__)
|
||||
stylesheet += QStringLiteral("font-family: 'Monaco';");
|
||||
#else
|
||||
stylesheet += QStringLiteral("font-family: 'Monospace';");
|
||||
#endif
|
||||
}
|
||||
|
||||
// HACK: Make the font size smaller without applying a stylesheet to the
|
||||
// whole window (which would impact performance).
|
||||
if (g_debugger_window)
|
||||
stylesheet += QString("font-size: %1pt;").arg(g_debugger_window->fontSize());
|
||||
|
||||
setStyleSheet(stylesheet);
|
||||
}
|
||||
|
||||
void DebuggerWidget::goToInDisassembler(u32 address, bool switch_to_tab)
|
||||
{
|
||||
DebuggerEvents::GoToAddress event;
|
||||
event.address = address;
|
||||
event.filter = DebuggerEvents::GoToAddress::DISASSEMBLER;
|
||||
event.switch_to_tab = switch_to_tab;
|
||||
DebuggerWidget::sendEvent(std::move(event));
|
||||
}
|
||||
|
||||
void DebuggerWidget::goToInMemoryView(u32 address, bool switch_to_tab)
|
||||
{
|
||||
DebuggerEvents::GoToAddress event;
|
||||
event.address = address;
|
||||
event.filter = DebuggerEvents::GoToAddress::MEMORY_VIEW;
|
||||
event.switch_to_tab = switch_to_tab;
|
||||
DebuggerWidget::sendEvent(std::move(event));
|
||||
}
|
||||
|
||||
void DebuggerWidget::sendEventImplementation(const DebuggerEvents::Event& event)
|
||||
{
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
for (const auto& [unique_name, widget] : g_debugger_window->dockManager().debuggerWidgets())
|
||||
if (widget->isPrimary() && widget->handleEvent(event))
|
||||
return;
|
||||
|
||||
for (const auto& [unique_name, widget] : g_debugger_window->dockManager().debuggerWidgets())
|
||||
if (!widget->isPrimary() && widget->handleEvent(event))
|
||||
return;
|
||||
}
|
||||
|
||||
void DebuggerWidget::broadcastEventImplementation(const DebuggerEvents::Event& event)
|
||||
{
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
for (const auto& [unique_name, widget] : g_debugger_window->dockManager().debuggerWidgets())
|
||||
widget->handleEvent(event);
|
||||
}
|
||||
|
||||
std::vector<QAction*> DebuggerWidget::createEventActionsImplementation(
|
||||
QMenu* menu,
|
||||
u32 max_top_level_actions,
|
||||
bool skip_self,
|
||||
const char* event_type,
|
||||
const char* action_prefix,
|
||||
std::function<const DebuggerEvents::Event*()> event_func)
|
||||
{
|
||||
if (!g_debugger_window)
|
||||
return {};
|
||||
|
||||
std::vector<DebuggerWidget*> receivers;
|
||||
for (const auto& [unique_name, widget] : g_debugger_window->dockManager().debuggerWidgets())
|
||||
if ((!skip_self || widget != this) && widget->acceptsEventType(event_type))
|
||||
receivers.emplace_back(widget);
|
||||
|
||||
std::sort(receivers.begin(), receivers.end(), [&](const DebuggerWidget* lhs, const DebuggerWidget* rhs) {
|
||||
if (lhs->displayNameWithoutSuffix() == rhs->displayNameWithoutSuffix())
|
||||
return lhs->displayNameSuffixNumber() < rhs->displayNameSuffixNumber();
|
||||
|
||||
return lhs->displayNameWithoutSuffix() < rhs->displayNameWithoutSuffix();
|
||||
});
|
||||
|
||||
QMenu* submenu = nullptr;
|
||||
if (receivers.size() > max_top_level_actions)
|
||||
{
|
||||
QString title_format = QCoreApplication::translate("DebuggerEvent", "%1...");
|
||||
submenu = new QMenu(title_format.arg(QCoreApplication::translate("DebuggerEvent", action_prefix)), menu);
|
||||
}
|
||||
|
||||
std::vector<QAction*> actions;
|
||||
for (size_t i = 0; i < receivers.size(); i++)
|
||||
{
|
||||
DebuggerWidget* receiver = receivers[i];
|
||||
|
||||
QAction* action;
|
||||
if (!submenu || i + 1 < max_top_level_actions)
|
||||
{
|
||||
QString title_format = QCoreApplication::translate("DebuggerEvent", "%1 %2");
|
||||
QString event_title = QCoreApplication::translate("DebuggerEvent", action_prefix);
|
||||
QString title = title_format.arg(event_title).arg(receiver->displayName());
|
||||
action = new QAction(title, menu);
|
||||
menu->addAction(action);
|
||||
}
|
||||
else
|
||||
{
|
||||
action = new QAction(receiver->displayName(), submenu);
|
||||
submenu->addAction(action);
|
||||
}
|
||||
|
||||
connect(action, &QAction::triggered, receiver, [receiver, event_func]() {
|
||||
const DebuggerEvents::Event* event = event_func();
|
||||
if (event)
|
||||
receiver->handleEvent(*event);
|
||||
});
|
||||
|
||||
actions.emplace_back(action);
|
||||
}
|
||||
|
||||
if (submenu)
|
||||
menu->addMenu(submenu);
|
||||
|
||||
return actions;
|
||||
}
|
||||
198
pcsx2-qt/Debugger/DebuggerWidget.h
Normal file
198
pcsx2-qt/Debugger/DebuggerWidget.h
Normal file
@@ -0,0 +1,198 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "QtHost.h"
|
||||
#include "Debugger/DebuggerEvents.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
class JsonValueWrapper;
|
||||
|
||||
// Container for variables to be passed to the constructor of DebuggerWidget.
|
||||
struct DebuggerWidgetParameters
|
||||
{
|
||||
QString unique_name;
|
||||
DebugInterface* cpu = nullptr;
|
||||
std::optional<BreakPointCpu> cpu_override;
|
||||
QWidget* parent = nullptr;
|
||||
};
|
||||
|
||||
// The base class for the contents of the dock widgets in the debugger.
|
||||
class DebuggerWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QString uniqueName() const;
|
||||
|
||||
// Get the translated name that should be displayed for this widget.
|
||||
QString displayName() const;
|
||||
QString displayNameWithoutSuffix() const;
|
||||
|
||||
QString customDisplayName() const;
|
||||
bool setCustomDisplayName(QString display_name);
|
||||
|
||||
bool isPrimary() const;
|
||||
void setPrimary(bool is_primary);
|
||||
|
||||
// Get the effective debug interface associated with this particular widget
|
||||
// if it's set, otherwise return the one associated with the layout that
|
||||
// contains this widget.
|
||||
DebugInterface& cpu() const;
|
||||
|
||||
// Set the debug interface associated with the layout. If false is returned,
|
||||
// we have to recreate the object.
|
||||
bool setCpu(DebugInterface& new_cpu);
|
||||
|
||||
// Get the CPU associated with this particular widget.
|
||||
std::optional<BreakPointCpu> cpuOverride() const;
|
||||
|
||||
// Set the CPU associated with the individual dock widget. If false is
|
||||
// returned, we have to recreate the object.
|
||||
bool setCpuOverride(std::optional<BreakPointCpu> new_cpu);
|
||||
|
||||
// Send each open debugger widget an event in turn, until one handles it.
|
||||
template <typename Event>
|
||||
static void sendEvent(Event event)
|
||||
{
|
||||
if (!QtHost::IsOnUIThread())
|
||||
{
|
||||
QtHost::RunOnUIThread([event = std::move(event)]() {
|
||||
DebuggerWidget::sendEventImplementation(event);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
sendEventImplementation(event);
|
||||
}
|
||||
|
||||
// Send all open debugger widgets an event.
|
||||
template <typename Event>
|
||||
static void broadcastEvent(Event event)
|
||||
{
|
||||
if (!QtHost::IsOnUIThread())
|
||||
{
|
||||
QtHost::RunOnUIThread([event = std::move(event)]() {
|
||||
DebuggerWidget::broadcastEventImplementation(event);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
broadcastEventImplementation(event);
|
||||
}
|
||||
|
||||
// Register a handler callback for the specified type of event.
|
||||
template <typename Event>
|
||||
void receiveEvent(std::function<bool(const Event&)> callback)
|
||||
{
|
||||
m_event_handlers.emplace(
|
||||
typeid(Event).name(),
|
||||
[callback](const DebuggerEvents::Event& event) -> bool {
|
||||
return callback(static_cast<const Event&>(event));
|
||||
});
|
||||
}
|
||||
|
||||
// Register a handler member function for the specified type of event.
|
||||
template <typename Event, typename SubClass>
|
||||
void receiveEvent(bool (SubClass::*function)(const Event& event))
|
||||
{
|
||||
m_event_handlers.emplace(
|
||||
typeid(Event).name(),
|
||||
[this, function](const DebuggerEvents::Event& event) -> bool {
|
||||
return (*static_cast<SubClass*>(this).*function)(static_cast<const Event&>(event));
|
||||
});
|
||||
}
|
||||
|
||||
// Call the handler callback for the specified event.
|
||||
bool handleEvent(const DebuggerEvents::Event& event);
|
||||
|
||||
// Check if this debugger widget can receive the specified type of event.
|
||||
bool acceptsEventType(const char* event_type);
|
||||
|
||||
// Generates context menu actions to send an event to each debugger widget
|
||||
// that can receive it. A submenu is generated if the number of possible
|
||||
// receivers exceeds max_top_level_actions. If skip_self is true, actions
|
||||
// are only generated if the sender and receiver aren't the same object.
|
||||
template <typename Event>
|
||||
std::vector<QAction*> createEventActions(
|
||||
QMenu* menu,
|
||||
std::function<std::optional<Event>()> event_func,
|
||||
bool skip_self = true,
|
||||
u32 max_top_level_actions = 5)
|
||||
{
|
||||
return createEventActionsImplementation(
|
||||
menu, max_top_level_actions, skip_self, typeid(Event).name(), Event::ACTION_PREFIX,
|
||||
[event_func]() -> DebuggerEvents::Event* {
|
||||
static std::optional<Event> event;
|
||||
event = event_func();
|
||||
if (!event.has_value())
|
||||
return nullptr;
|
||||
|
||||
return static_cast<DebuggerEvents::Event*>(&(*event));
|
||||
});
|
||||
}
|
||||
|
||||
virtual void toJson(JsonValueWrapper& json);
|
||||
virtual bool fromJson(const JsonValueWrapper& json);
|
||||
|
||||
void switchToThisTab();
|
||||
|
||||
bool supportsMultipleInstances();
|
||||
|
||||
void retranslateDisplayName();
|
||||
|
||||
std::optional<int> displayNameSuffixNumber() const;
|
||||
void setDisplayNameSuffixNumber(std::optional<int> suffix_number);
|
||||
|
||||
void updateStyleSheet();
|
||||
|
||||
static void goToInDisassembler(u32 address, bool switch_to_tab);
|
||||
static void goToInMemoryView(u32 address, bool switch_to_tab);
|
||||
|
||||
protected:
|
||||
enum Flags
|
||||
{
|
||||
NO_DEBUGGER_FLAGS = 0,
|
||||
// Prevent the user from opening multiple dock widgets of this type.
|
||||
DISALLOW_MULTIPLE_INSTANCES = 1 << 0,
|
||||
// Apply a stylesheet that gives all the text a monospace font.
|
||||
MONOSPACE_FONT = 1 << 1
|
||||
};
|
||||
|
||||
DebuggerWidget(const DebuggerWidgetParameters& parameters, u32 flags);
|
||||
|
||||
private:
|
||||
static void sendEventImplementation(const DebuggerEvents::Event& event);
|
||||
static void broadcastEventImplementation(const DebuggerEvents::Event& event);
|
||||
|
||||
std::vector<QAction*> createEventActionsImplementation(
|
||||
QMenu* menu,
|
||||
u32 max_top_level_actions,
|
||||
bool skip_self,
|
||||
const char* event_type,
|
||||
const char* action_prefix,
|
||||
std::function<const DebuggerEvents::Event*()> event_func);
|
||||
|
||||
QString m_unique_name;
|
||||
|
||||
// A user-defined name, or an empty string if no name was specified so that
|
||||
// the default names can be retranslated on the fly.
|
||||
QString m_custom_display_name;
|
||||
|
||||
QString m_translated_display_name;
|
||||
std::optional<int> m_display_name_suffix_number;
|
||||
|
||||
// Primary debugger widgets will be chosen to handle events first. For
|
||||
// example, clicking on an address to go to it in the primary memory view.
|
||||
bool m_is_primary = false;
|
||||
|
||||
DebugInterface* m_cpu;
|
||||
std::optional<BreakPointCpu> m_cpu_override;
|
||||
u32 m_flags;
|
||||
|
||||
std::multimap<std::string, std::function<bool(const DebuggerEvents::Event&)>> m_event_handlers;
|
||||
};
|
||||
@@ -3,109 +3,373 @@
|
||||
|
||||
#include "DebuggerWindow.h"
|
||||
|
||||
#include "Debugger/DebuggerWidget.h"
|
||||
#include "Debugger/Docking/DockManager.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
#include "DebugTools/MIPSAnalyst.h"
|
||||
#include "DebugTools/MipsStackWalk.h"
|
||||
#include "DebugTools/SymbolImporter.h"
|
||||
#include "VMManager.h"
|
||||
#include "QtHost.h"
|
||||
#include "MainWindow.h"
|
||||
#include "AnalysisOptionsDialog.h"
|
||||
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
DebuggerWindow* g_debugger_window = nullptr;
|
||||
|
||||
DebuggerWindow::DebuggerWindow(QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
: KDDockWidgets::QtWidgets::MainWindow(QStringLiteral("DebuggerWindow"), {}, parent)
|
||||
, m_dock_manager(new DockManager(this))
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
// Easiest way to handle cross platform monospace fonts
|
||||
// There are issues related to TabWidget -> Children font inheritance otherwise
|
||||
#if defined(WIN32)
|
||||
m_ui.cpuTabs->setStyleSheet(QStringLiteral("font: 8pt 'Lucida Console'"));
|
||||
#elif defined(__APPLE__)
|
||||
m_ui.cpuTabs->setStyleSheet(QStringLiteral("font: 10pt 'Monaco'"));
|
||||
#else
|
||||
m_ui.cpuTabs->setStyleSheet(QStringLiteral("font: 8pt 'Monospace'"));
|
||||
#endif
|
||||
g_debugger_window = this;
|
||||
|
||||
setupDefaultToolBarState();
|
||||
setupFonts();
|
||||
restoreWindowGeometry();
|
||||
|
||||
m_dock_manager->loadLayouts();
|
||||
|
||||
connect(m_ui.actionAnalyse, &QAction::triggered, this, &DebuggerWindow::onAnalyse);
|
||||
connect(m_ui.actionSettings, &QAction::triggered, this, &DebuggerWindow::onSettings);
|
||||
connect(m_ui.actionGameSettings, &QAction::triggered, this, &DebuggerWindow::onGameSettings);
|
||||
connect(m_ui.actionClose, &QAction::triggered, this, &DebuggerWindow::close);
|
||||
|
||||
connect(m_ui.actionOnTop, &QAction::triggered, this, [this](bool checked) {
|
||||
if (checked)
|
||||
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
else
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
|
||||
show();
|
||||
});
|
||||
|
||||
connect(m_ui.actionRun, &QAction::triggered, this, &DebuggerWindow::onRunPause);
|
||||
connect(m_ui.actionStepInto, &QAction::triggered, this, &DebuggerWindow::onStepInto);
|
||||
connect(m_ui.actionStepOver, &QAction::triggered, this, &DebuggerWindow::onStepOver);
|
||||
connect(m_ui.actionStepOut, &QAction::triggered, this, &DebuggerWindow::onStepOut);
|
||||
connect(m_ui.actionAnalyse, &QAction::triggered, this, &DebuggerWindow::onAnalyse);
|
||||
connect(m_ui.actionOnTop, &QAction::triggered, [this] { this->setWindowFlags(this->windowFlags() ^ Qt::WindowStaysOnTopHint); this->show(); });
|
||||
|
||||
connect(g_emu_thread, &EmuThread::onVMPaused, this, &DebuggerWindow::onVMStateChanged);
|
||||
connect(g_emu_thread, &EmuThread::onVMResumed, this, &DebuggerWindow::onVMStateChanged);
|
||||
connect(m_ui.actionShutDown, &QAction::triggered, [this]() {
|
||||
if (currentCPU() && currentCPU()->isAlive())
|
||||
g_emu_thread->shutdownVM(false);
|
||||
});
|
||||
|
||||
onVMStateChanged(); // If we missed a state change while we weren't loaded
|
||||
connect(m_ui.actionReset, &QAction::triggered, [this]() {
|
||||
if (currentCPU() && currentCPU()->isAlive())
|
||||
g_emu_thread->resetVM();
|
||||
});
|
||||
|
||||
// We can't do this in the designer, but we want to right align the actionOnTop action in the toolbar
|
||||
QWidget* spacer = new QWidget(this);
|
||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_ui.toolBar->insertWidget(m_ui.actionAnalyse, spacer);
|
||||
connect(m_ui.menuTools, &QMenu::aboutToShow, this, [this]() {
|
||||
m_dock_manager->createToolsMenu(m_ui.menuTools);
|
||||
});
|
||||
|
||||
m_cpuWidget_r5900 = new CpuWidget(this, r5900Debug);
|
||||
m_cpuWidget_r3000 = new CpuWidget(this, r3000Debug);
|
||||
connect(m_ui.menuWindows, &QMenu::aboutToShow, this, [this]() {
|
||||
m_dock_manager->createWindowsMenu(m_ui.menuWindows);
|
||||
});
|
||||
|
||||
m_ui.cpuTabs->addTab(m_cpuWidget_r5900, "R5900");
|
||||
m_ui.cpuTabs->addTab(m_cpuWidget_r3000, "R3000");
|
||||
}
|
||||
connect(m_ui.actionResetAllLayouts, &QAction::triggered, this, [this]() {
|
||||
QString text = tr("Are you sure you want to reset all layouts?");
|
||||
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
DebuggerWindow::~DebuggerWindow() = default;
|
||||
m_dock_manager->resetAllLayouts();
|
||||
});
|
||||
|
||||
// There is no straightforward way to set the tab text to bold in Qt
|
||||
// Sorry colour blind people, but this is the best we can do for now
|
||||
void DebuggerWindow::setTabActiveStyle(BreakPointCpu enabledCpu)
|
||||
{
|
||||
m_ui.cpuTabs->tabBar()->setTabTextColor(m_ui.cpuTabs->indexOf(m_cpuWidget_r5900), (enabledCpu == BREAKPOINT_EE) ? Qt::red : this->palette().text().color());
|
||||
m_ui.cpuTabs->tabBar()->setTabTextColor(m_ui.cpuTabs->indexOf(m_cpuWidget_r3000), (enabledCpu == BREAKPOINT_IOP) ? Qt::red : this->palette().text().color());
|
||||
}
|
||||
connect(m_ui.actionResetDefaultLayouts, &QAction::triggered, this, [this]() {
|
||||
QString text = tr("Are you sure you want to reset the default layouts?");
|
||||
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
void DebuggerWindow::onVMStateChanged()
|
||||
{
|
||||
if (!QtHost::IsVMPaused())
|
||||
m_dock_manager->resetDefaultLayouts();
|
||||
});
|
||||
|
||||
connect(g_emu_thread, &EmuThread::onVMPaused, this, []() {
|
||||
DebuggerWidget::broadcastEvent(DebuggerEvents::VMUpdate());
|
||||
});
|
||||
|
||||
connect(g_emu_thread, &EmuThread::onVMStarting, this, &DebuggerWindow::onVMStarting);
|
||||
connect(g_emu_thread, &EmuThread::onVMPaused, this, &DebuggerWindow::onVMPaused);
|
||||
connect(g_emu_thread, &EmuThread::onVMResumed, this, &DebuggerWindow::onVMResumed);
|
||||
connect(g_emu_thread, &EmuThread::onVMStopped, this, &DebuggerWindow::onVMStopped);
|
||||
|
||||
if (QtHost::IsVMValid())
|
||||
{
|
||||
m_ui.actionRun->setText(tr("Pause"));
|
||||
m_ui.actionRun->setIcon(QIcon::fromTheme(QStringLiteral("pause-line")));
|
||||
m_ui.actionStepInto->setEnabled(false);
|
||||
m_ui.actionStepOver->setEnabled(false);
|
||||
m_ui.actionStepOut->setEnabled(false);
|
||||
setTabActiveStyle(BREAKPOINT_IOP_AND_EE);
|
||||
onVMStarting();
|
||||
|
||||
if (QtHost::IsVMPaused())
|
||||
onVMPaused();
|
||||
else
|
||||
onVMResumed();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.actionRun->setText(tr("Run"));
|
||||
m_ui.actionRun->setIcon(QIcon::fromTheme(QStringLiteral("play-line")));
|
||||
m_ui.actionStepInto->setEnabled(true);
|
||||
m_ui.actionStepOver->setEnabled(true);
|
||||
m_ui.actionStepOut->setEnabled(true);
|
||||
// Switch to the CPU tab that triggered the breakpoint
|
||||
// Also bold the tab text to indicate that a breakpoint was triggered
|
||||
if (CBreakPoints::GetBreakpointTriggered())
|
||||
{
|
||||
const BreakPointCpu triggeredCpu = CBreakPoints::GetBreakpointTriggeredCpu();
|
||||
setTabActiveStyle(triggeredCpu);
|
||||
switch (triggeredCpu)
|
||||
{
|
||||
case BREAKPOINT_EE:
|
||||
m_ui.cpuTabs->setCurrentWidget(m_cpuWidget_r5900);
|
||||
break;
|
||||
case BREAKPOINT_IOP:
|
||||
m_ui.cpuTabs->setCurrentWidget(m_cpuWidget_r3000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Host::RunOnCPUThread([] {
|
||||
CBreakPoints::ClearTemporaryBreakPoints();
|
||||
CBreakPoints::SetBreakpointTriggered(false, BREAKPOINT_IOP_AND_EE);
|
||||
// Our current PC is on a breakpoint.
|
||||
// When we run the core again, we want to skip this breakpoint and run
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, r5900Debug.getPC());
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, r3000Debug.getPC());
|
||||
});
|
||||
}
|
||||
onVMStopped();
|
||||
}
|
||||
return;
|
||||
|
||||
m_dock_manager->switchToLayout(0);
|
||||
|
||||
QMenuBar* menu_bar = menuBar();
|
||||
|
||||
setMenuWidget(m_dock_manager->createLayoutSwitcher(menu_bar));
|
||||
|
||||
Host::RunOnCPUThread([]() {
|
||||
R5900SymbolImporter.OnDebuggerOpened();
|
||||
});
|
||||
|
||||
QTimer* refresh_timer = new QTimer(this);
|
||||
connect(refresh_timer, &QTimer::timeout, this, []() {
|
||||
DebuggerWidget::broadcastEvent(DebuggerEvents::Refresh());
|
||||
});
|
||||
refresh_timer->start(1000);
|
||||
}
|
||||
|
||||
DebuggerWindow* DebuggerWindow::getInstance()
|
||||
{
|
||||
if (!g_debugger_window)
|
||||
createInstance();
|
||||
|
||||
return g_debugger_window;
|
||||
}
|
||||
|
||||
DebuggerWindow* DebuggerWindow::createInstance()
|
||||
{
|
||||
// Setup KDDockWidgets.
|
||||
DockManager::configureDockingSystem();
|
||||
|
||||
if (g_debugger_window)
|
||||
destroyInstance();
|
||||
|
||||
return new DebuggerWindow(nullptr);
|
||||
}
|
||||
|
||||
void DebuggerWindow::destroyInstance()
|
||||
{
|
||||
if (g_debugger_window)
|
||||
g_debugger_window->close();
|
||||
}
|
||||
|
||||
bool DebuggerWindow::shouldShowOnStartup()
|
||||
{
|
||||
return Host::GetBaseBoolSettingValue("Debugger/UserInterface", "ShowOnStartup", false);
|
||||
}
|
||||
|
||||
DockManager& DebuggerWindow::dockManager()
|
||||
{
|
||||
return *m_dock_manager;
|
||||
}
|
||||
|
||||
void DebuggerWindow::setupDefaultToolBarState()
|
||||
{
|
||||
// Hiding all the toolbars lets us save the default state of the window with
|
||||
// all the toolbars hidden. The DockManager will show the appropriate ones
|
||||
// later anyway.
|
||||
for (QToolBar* toolbar : findChildren<QToolBar*>())
|
||||
toolbar->hide();
|
||||
|
||||
m_default_toolbar_state = saveState();
|
||||
|
||||
for (QToolBar* toolbar : findChildren<QToolBar*>())
|
||||
connect(toolbar, &QToolBar::topLevelChanged, m_dock_manager, &DockManager::updateToolBarLockState);
|
||||
}
|
||||
|
||||
void DebuggerWindow::clearToolBarState()
|
||||
{
|
||||
restoreState(m_default_toolbar_state);
|
||||
}
|
||||
|
||||
void DebuggerWindow::setupFonts()
|
||||
{
|
||||
m_font_size = Host::GetBaseIntSettingValue("Debugger/UserInterface", "FontSize", DEFAULT_FONT_SIZE);
|
||||
if (m_font_size < MINIMUM_FONT_SIZE || m_font_size > MAXIMUM_FONT_SIZE)
|
||||
m_font_size = DEFAULT_FONT_SIZE;
|
||||
|
||||
m_ui.actionIncreaseFontSize->setShortcuts(QKeySequence::ZoomIn);
|
||||
connect(m_ui.actionIncreaseFontSize, &QAction::triggered, this, [this]() {
|
||||
if (m_font_size >= MAXIMUM_FONT_SIZE)
|
||||
return;
|
||||
|
||||
m_font_size++;
|
||||
|
||||
updateFontActions();
|
||||
updateStyleSheets();
|
||||
saveFontSize();
|
||||
});
|
||||
|
||||
m_ui.actionDecreaseFontSize->setShortcut(QKeySequence::ZoomOut);
|
||||
connect(m_ui.actionDecreaseFontSize, &QAction::triggered, this, [this]() {
|
||||
if (m_font_size <= MINIMUM_FONT_SIZE)
|
||||
return;
|
||||
|
||||
m_font_size--;
|
||||
|
||||
updateFontActions();
|
||||
updateStyleSheets();
|
||||
saveFontSize();
|
||||
});
|
||||
|
||||
connect(m_ui.actionResetFontSize, &QAction::triggered, this, [this]() {
|
||||
m_font_size = DEFAULT_FONT_SIZE;
|
||||
|
||||
updateFontActions();
|
||||
updateStyleSheets();
|
||||
saveFontSize();
|
||||
});
|
||||
|
||||
updateFontActions();
|
||||
updateStyleSheets();
|
||||
}
|
||||
|
||||
void DebuggerWindow::updateFontActions()
|
||||
{
|
||||
m_ui.actionIncreaseFontSize->setEnabled(m_font_size < MAXIMUM_FONT_SIZE);
|
||||
m_ui.actionDecreaseFontSize->setEnabled(m_font_size > MINIMUM_FONT_SIZE);
|
||||
m_ui.actionResetFontSize->setEnabled(m_font_size != DEFAULT_FONT_SIZE);
|
||||
}
|
||||
|
||||
void DebuggerWindow::saveFontSize()
|
||||
{
|
||||
Host::SetBaseIntSettingValue("Debugger/UserInterface", "FontSize", m_font_size);
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
|
||||
int DebuggerWindow::fontSize()
|
||||
{
|
||||
return m_font_size;
|
||||
}
|
||||
|
||||
void DebuggerWindow::updateStyleSheets()
|
||||
{
|
||||
// TODO: Migrate away from stylesheets to improve performance.
|
||||
if (m_font_size != DEFAULT_FONT_SIZE)
|
||||
{
|
||||
int size = m_font_size + QApplication::font().pointSize() - DEFAULT_FONT_SIZE;
|
||||
setStyleSheet(QString("* { font-size: %1pt; } QTabBar { font-size: %2pt; }").arg(size).arg(size + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
setStyleSheet(QString());
|
||||
}
|
||||
|
||||
dockManager().updateStyleSheets();
|
||||
}
|
||||
|
||||
void DebuggerWindow::saveWindowGeometry()
|
||||
{
|
||||
std::string old_geometry = Host::GetBaseStringSettingValue("Debugger/UserInterface", "WindowGeometry");
|
||||
|
||||
std::string geometry;
|
||||
if (shouldSaveWindowGeometry())
|
||||
geometry = saveGeometry().toBase64().toStdString();
|
||||
|
||||
if (geometry != old_geometry)
|
||||
{
|
||||
Host::SetBaseStringSettingValue("Debugger/UserInterface", "WindowGeometry", geometry.c_str());
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerWindow::restoreWindowGeometry()
|
||||
{
|
||||
if (!shouldSaveWindowGeometry())
|
||||
return;
|
||||
|
||||
std::string geometry = Host::GetBaseStringSettingValue("Debugger/UserInterface", "WindowGeometry");
|
||||
restoreGeometry(QByteArray::fromBase64(QByteArray::fromStdString(geometry)));
|
||||
}
|
||||
|
||||
bool DebuggerWindow::shouldSaveWindowGeometry()
|
||||
{
|
||||
return Host::GetBaseBoolSettingValue("Debugger/UserInterface", "SaveWindowGeometry", true);
|
||||
}
|
||||
|
||||
void DebuggerWindow::onVMStarting()
|
||||
{
|
||||
m_ui.actionRun->setEnabled(true);
|
||||
m_ui.actionStepInto->setEnabled(true);
|
||||
m_ui.actionStepOver->setEnabled(true);
|
||||
m_ui.actionStepOut->setEnabled(true);
|
||||
|
||||
m_ui.actionAnalyse->setEnabled(true);
|
||||
m_ui.actionGameSettings->setEnabled(true);
|
||||
|
||||
m_ui.actionShutDown->setEnabled(true);
|
||||
m_ui.actionReset->setEnabled(true);
|
||||
}
|
||||
|
||||
void DebuggerWindow::onVMPaused()
|
||||
{
|
||||
m_ui.actionRun->setText(tr("Run"));
|
||||
m_ui.actionRun->setIcon(QIcon::fromTheme(QStringLiteral("play-line")));
|
||||
m_ui.actionStepInto->setEnabled(true);
|
||||
m_ui.actionStepOver->setEnabled(true);
|
||||
m_ui.actionStepOut->setEnabled(true);
|
||||
|
||||
// Switch to the CPU tab that triggered the breakpoint.
|
||||
// Also blink the tab text to indicate that a breakpoint was triggered.
|
||||
if (CBreakPoints::GetBreakpointTriggered())
|
||||
{
|
||||
const BreakPointCpu triggeredCpu = CBreakPoints::GetBreakpointTriggeredCpu();
|
||||
m_dock_manager->switchToLayoutWithCPU(triggeredCpu, true);
|
||||
|
||||
Host::RunOnCPUThread([] {
|
||||
CBreakPoints::ClearTemporaryBreakPoints();
|
||||
CBreakPoints::SetBreakpointTriggered(false, BREAKPOINT_IOP_AND_EE);
|
||||
|
||||
// Our current PC is on a breakpoint.
|
||||
// When we run the core again, we want to skip this breakpoint and run.
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, r5900Debug.getPC());
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, r3000Debug.getPC());
|
||||
});
|
||||
}
|
||||
|
||||
// Stops us from telling the disassembly widget to jump somwhere because
|
||||
// breakpoint code paused the core.
|
||||
if (!CBreakPoints::GetCorePaused())
|
||||
emit onVMActuallyPaused();
|
||||
else
|
||||
CBreakPoints::SetCorePaused(false);
|
||||
}
|
||||
|
||||
void DebuggerWindow::onVMResumed()
|
||||
{
|
||||
m_ui.actionRun->setText(tr("Pause"));
|
||||
m_ui.actionRun->setIcon(QIcon::fromTheme(QStringLiteral("pause-line")));
|
||||
m_ui.actionStepInto->setEnabled(false);
|
||||
m_ui.actionStepOver->setEnabled(false);
|
||||
m_ui.actionStepOut->setEnabled(false);
|
||||
}
|
||||
|
||||
void DebuggerWindow::onVMStopped()
|
||||
{
|
||||
m_ui.actionRun->setEnabled(false);
|
||||
m_ui.actionStepInto->setEnabled(false);
|
||||
m_ui.actionStepOver->setEnabled(false);
|
||||
m_ui.actionStepOut->setEnabled(false);
|
||||
|
||||
m_ui.actionAnalyse->setEnabled(false);
|
||||
m_ui.actionGameSettings->setEnabled(false);
|
||||
|
||||
m_ui.actionShutDown->setEnabled(false);
|
||||
m_ui.actionReset->setEnabled(false);
|
||||
}
|
||||
|
||||
void DebuggerWindow::onAnalyse()
|
||||
{
|
||||
AnalysisOptionsDialog* dialog = new AnalysisOptionsDialog(this);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
void DebuggerWindow::onSettings()
|
||||
{
|
||||
g_main_window->doSettings("Debug");
|
||||
}
|
||||
|
||||
void DebuggerWindow::onGameSettings()
|
||||
{
|
||||
g_main_window->doGameSettings("Debug");
|
||||
}
|
||||
|
||||
void DebuggerWindow::onRunPause()
|
||||
@@ -115,40 +379,162 @@ void DebuggerWindow::onRunPause()
|
||||
|
||||
void DebuggerWindow::onStepInto()
|
||||
{
|
||||
CpuWidget* currentCpu = static_cast<CpuWidget*>(m_ui.cpuTabs->currentWidget());
|
||||
currentCpu->onStepInto();
|
||||
DebugInterface* cpu = currentCPU();
|
||||
if (!cpu)
|
||||
return;
|
||||
|
||||
if (!cpu->isAlive() || !cpu->isCpuPaused())
|
||||
return;
|
||||
|
||||
// Allow the cpu to skip this pc if it is a breakpoint
|
||||
CBreakPoints::SetSkipFirst(cpu->getCpuType(), cpu->getPC());
|
||||
|
||||
const u32 pc = cpu->getPC();
|
||||
const MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(cpu, pc);
|
||||
|
||||
u32 bpAddr = pc + 0x4; // Default to the next instruction
|
||||
|
||||
if (info.isBranch)
|
||||
{
|
||||
if (!info.isConditional)
|
||||
{
|
||||
bpAddr = info.branchTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info.conditionMet)
|
||||
{
|
||||
bpAddr = info.branchTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
bpAddr = pc + (2 * 4); // Skip branch delay slot
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info.isSyscall)
|
||||
bpAddr = info.branchTarget; // Syscalls are always taken
|
||||
|
||||
Host::RunOnCPUThread([cpu, bpAddr] {
|
||||
CBreakPoints::AddBreakPoint(cpu->getCpuType(), bpAddr, true);
|
||||
cpu->resumeCpu();
|
||||
});
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
void DebuggerWindow::onStepOver()
|
||||
{
|
||||
CpuWidget* currentCpu = static_cast<CpuWidget*>(m_ui.cpuTabs->currentWidget());
|
||||
currentCpu->onStepOver();
|
||||
DebugInterface* cpu = currentCPU();
|
||||
if (!cpu)
|
||||
return;
|
||||
|
||||
if (!cpu->isAlive() || !cpu->isCpuPaused())
|
||||
return;
|
||||
|
||||
const u32 pc = cpu->getPC();
|
||||
const MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(cpu, pc);
|
||||
|
||||
u32 bpAddr = pc + 0x4; // Default to the next instruction
|
||||
|
||||
if (info.isBranch)
|
||||
{
|
||||
if (!info.isConditional)
|
||||
{
|
||||
if (info.isLinkedBranch) // jal, jalr
|
||||
{
|
||||
// it's a function call with a delay slot - skip that too
|
||||
bpAddr += 4;
|
||||
}
|
||||
else // j, ...
|
||||
{
|
||||
// in case of absolute branches, set the breakpoint at the branch target
|
||||
bpAddr = info.branchTarget;
|
||||
}
|
||||
}
|
||||
else // beq, ...
|
||||
{
|
||||
if (info.conditionMet)
|
||||
{
|
||||
bpAddr = info.branchTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
bpAddr = pc + (2 * 4); // Skip branch delay slot
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Host::RunOnCPUThread([cpu, bpAddr] {
|
||||
CBreakPoints::AddBreakPoint(cpu->getCpuType(), bpAddr, true);
|
||||
cpu->resumeCpu();
|
||||
});
|
||||
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void DebuggerWindow::onStepOut()
|
||||
{
|
||||
CpuWidget* currentCpu = static_cast<CpuWidget*>(m_ui.cpuTabs->currentWidget());
|
||||
currentCpu->onStepOut();
|
||||
}
|
||||
DebugInterface* cpu = currentCPU();
|
||||
if (!cpu)
|
||||
return;
|
||||
|
||||
void DebuggerWindow::onAnalyse()
|
||||
{
|
||||
AnalysisOptionsDialog* dialog = new AnalysisOptionsDialog(this);
|
||||
dialog->show();
|
||||
}
|
||||
if (!cpu->isAlive() || !cpu->isCpuPaused())
|
||||
return;
|
||||
|
||||
void DebuggerWindow::showEvent(QShowEvent* event)
|
||||
{
|
||||
Host::RunOnCPUThread([]() {
|
||||
R5900SymbolImporter.OnDebuggerOpened();
|
||||
// Allow the cpu to skip this pc if it is a breakpoint
|
||||
CBreakPoints::SetSkipFirst(cpu->getCpuType(), cpu->getPC());
|
||||
|
||||
std::vector<MipsStackWalk::StackFrame> stack_frames;
|
||||
for (const auto& thread : cpu->GetThreadList())
|
||||
{
|
||||
if (thread->Status() == ThreadStatus::THS_RUN)
|
||||
{
|
||||
stack_frames = MipsStackWalk::Walk(
|
||||
cpu,
|
||||
cpu->getPC(),
|
||||
cpu->getRegister(0, 31),
|
||||
cpu->getRegister(0, 29),
|
||||
thread->EntryPoint(),
|
||||
thread->StackTop());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stack_frames.size() < 2)
|
||||
return;
|
||||
|
||||
u32 breakpoint_pc = stack_frames.at(1).pc;
|
||||
|
||||
Host::RunOnCPUThread([cpu, breakpoint_pc] {
|
||||
CBreakPoints::AddBreakPoint(cpu->getCpuType(), breakpoint_pc, true);
|
||||
cpu->resumeCpu();
|
||||
});
|
||||
QMainWindow::showEvent(event);
|
||||
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void DebuggerWindow::hideEvent(QHideEvent* event)
|
||||
void DebuggerWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
dockManager().saveCurrentLayout();
|
||||
saveWindowGeometry();
|
||||
|
||||
Host::RunOnCPUThread([]() {
|
||||
R5900SymbolImporter.OnDebuggerClosed();
|
||||
});
|
||||
QMainWindow::hideEvent(event);
|
||||
|
||||
KDDockWidgets::QtWidgets::MainWindow::closeEvent(event);
|
||||
|
||||
g_debugger_window = nullptr;
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
DebugInterface* DebuggerWindow::currentCPU()
|
||||
{
|
||||
std::optional<BreakPointCpu> maybe_cpu = m_dock_manager->cpu();
|
||||
if (!maybe_cpu.has_value())
|
||||
return nullptr;
|
||||
|
||||
return &DebugInterface::get(*maybe_cpu);
|
||||
}
|
||||
|
||||
@@ -3,39 +3,75 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CpuWidget.h"
|
||||
|
||||
#include "ui_DebuggerWindow.h"
|
||||
|
||||
class DebuggerWindow : public QMainWindow
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
#include <kddockwidgets/MainWindow.h>
|
||||
|
||||
class DockManager;
|
||||
|
||||
class DebuggerWindow : public KDDockWidgets::QtWidgets::MainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DebuggerWindow(QWidget* parent);
|
||||
~DebuggerWindow();
|
||||
|
||||
static DebuggerWindow* getInstance();
|
||||
static DebuggerWindow* createInstance();
|
||||
static void destroyInstance();
|
||||
static bool shouldShowOnStartup();
|
||||
|
||||
DockManager& dockManager();
|
||||
|
||||
void setupDefaultToolBarState();
|
||||
void clearToolBarState();
|
||||
void setupFonts();
|
||||
void updateFontActions();
|
||||
void saveFontSize();
|
||||
int fontSize();
|
||||
void updateStyleSheets();
|
||||
|
||||
void saveWindowGeometry();
|
||||
void restoreWindowGeometry();
|
||||
bool shouldSaveWindowGeometry();
|
||||
|
||||
public slots:
|
||||
void onVMStateChanged();
|
||||
void onVMStarting();
|
||||
void onVMPaused();
|
||||
void onVMResumed();
|
||||
void onVMStopped();
|
||||
|
||||
void onAnalyse();
|
||||
void onSettings();
|
||||
void onGameSettings();
|
||||
void onRunPause();
|
||||
void onStepInto();
|
||||
void onStepOver();
|
||||
void onStepOut();
|
||||
void onAnalyse();
|
||||
|
||||
Q_SIGNALS:
|
||||
// Only emitted if the pause wasn't a temporary one triggered by the
|
||||
// breakpoint code.
|
||||
void onVMActuallyPaused();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event);
|
||||
void hideEvent(QHideEvent *event);
|
||||
void closeEvent(QCloseEvent* event);
|
||||
|
||||
private:
|
||||
DebugInterface* currentCPU();
|
||||
|
||||
Ui::DebuggerWindow m_ui;
|
||||
QAction* m_actionRunPause;
|
||||
QAction* m_actionStepInto;
|
||||
QAction* m_actionStepOver;
|
||||
QAction* m_actionStepOut;
|
||||
|
||||
CpuWidget* m_cpuWidget_r5900;
|
||||
CpuWidget* m_cpuWidget_r3000;
|
||||
DockManager* m_dock_manager;
|
||||
|
||||
void setTabActiveStyle(BreakPointCpu toggledCPU);
|
||||
QByteArray m_default_toolbar_state;
|
||||
|
||||
int m_font_size;
|
||||
static const constexpr int DEFAULT_FONT_SIZE = 10;
|
||||
static const constexpr int MINIMUM_FONT_SIZE = 5;
|
||||
static const constexpr int MAXIMUM_FONT_SIZE = 30;
|
||||
};
|
||||
|
||||
extern DebuggerWindow* g_debugger_window;
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
<width>1000</width>
|
||||
<height>750</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -18,31 +18,74 @@
|
||||
<normalon>:/icons/AppIcon64.png</normalon>
|
||||
</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="cpuTabs"/>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1000</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionAnalyse"/>
|
||||
<addaction name="actionSettings"/>
|
||||
<addaction name="actionGameSettings"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionClose"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuDebug">
|
||||
<property name="title">
|
||||
<string>Debug</string>
|
||||
</property>
|
||||
<addaction name="actionRun"/>
|
||||
<addaction name="actionStepInto"/>
|
||||
<addaction name="actionStepOver"/>
|
||||
<addaction name="actionStepOut"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuWindows">
|
||||
<property name="title">
|
||||
<string>Windows</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
<string>View</string>
|
||||
</property>
|
||||
<addaction name="actionOnTop"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionIncreaseFontSize"/>
|
||||
<addaction name="actionDecreaseFontSize"/>
|
||||
<addaction name="actionResetFontSize"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuLayouts">
|
||||
<property name="title">
|
||||
<string>Layouts</string>
|
||||
</property>
|
||||
<addaction name="actionResetAllLayouts"/>
|
||||
<addaction name="actionResetDefaultLayouts"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuView"/>
|
||||
<addaction name="menuDebug"/>
|
||||
<addaction name="menuTools"/>
|
||||
<addaction name="menuWindows"/>
|
||||
<addaction name="menuLayouts"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::ContextMenuPolicy::PreventContextMenu</enum>
|
||||
</property>
|
||||
<property name="movable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
<widget class="QToolBar" name="toolBarDebug">
|
||||
<property name="windowTitle">
|
||||
<string>Debug</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonStyle::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<property name="floatable">
|
||||
<bool>false</bool>
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
@@ -54,8 +97,57 @@
|
||||
<addaction name="actionStepInto"/>
|
||||
<addaction name="actionStepOver"/>
|
||||
<addaction name="actionStepOut"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBarFile">
|
||||
<property name="windowTitle">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionAnalyse"/>
|
||||
<addaction name="actionSettings"/>
|
||||
<addaction name="actionGameSettings"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBarSystem">
|
||||
<property name="windowTitle">
|
||||
<string>System</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionShutDown"/>
|
||||
<addaction name="actionReset"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBarView">
|
||||
<property name="windowTitle">
|
||||
<string>View</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionOnTop"/>
|
||||
<addaction name="actionIncreaseFontSize"/>
|
||||
<addaction name="actionDecreaseFontSize"/>
|
||||
<addaction name="actionResetFontSize"/>
|
||||
</widget>
|
||||
<action name="actionRun">
|
||||
<property name="icon">
|
||||
@@ -120,6 +212,112 @@
|
||||
<string>Analyze</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionResetAllLayouts">
|
||||
<property name="text">
|
||||
<string>Reset All Layouts</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionResetDefaultLayouts">
|
||||
<property name="text">
|
||||
<string>Reset Default Layouts</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionResetSplitterPositions">
|
||||
<property name="text">
|
||||
<string>Reset Splitter Positions</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionShutDown">
|
||||
<property name="icon">
|
||||
<iconset theme="shut-down-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Shut Down</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionReset">
|
||||
<property name="icon">
|
||||
<iconset theme="restart-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClose">
|
||||
<property name="icon">
|
||||
<iconset theme="close-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionIncreaseFontSize">
|
||||
<property name="icon">
|
||||
<iconset theme="zoom-in-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Increase Font Size</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDecreaseFontSize">
|
||||
<property name="icon">
|
||||
<iconset theme="zoom-out-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Decrease Font Size</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+-</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionResetFontSize">
|
||||
<property name="icon">
|
||||
<iconset theme="refresh-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset Font Size</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="settings-3-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGameSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="file-settings-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Game Settings</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
#include "DisassemblyWidget.h"
|
||||
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
#include "Debugger/JsonValueWrapper.h"
|
||||
#include "Debugger/Breakpoints/BreakpointModel.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/DisassemblyManager.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
@@ -10,6 +14,7 @@
|
||||
|
||||
#include "QtUtils.h"
|
||||
#include "QtHost.h"
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtGui/QClipboard>
|
||||
@@ -19,16 +24,73 @@
|
||||
|
||||
using namespace QtUtils;
|
||||
|
||||
DisassemblyWidget::DisassemblyWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
DisassemblyWidget::DisassemblyWidget(const DebuggerWidgetParameters& parameters)
|
||||
: DebuggerWidget(parameters, MONOSPACE_FONT)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
m_ui.setupUi(this);
|
||||
|
||||
connect(this, &DisassemblyWidget::customContextMenuRequested, this, &DisassemblyWidget::customMenuRequested);
|
||||
m_disassemblyManager.setCpu(&cpu());
|
||||
|
||||
setFocusPolicy(Qt::FocusPolicy::ClickFocus);
|
||||
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(this, &DisassemblyWidget::customContextMenuRequested, this, &DisassemblyWidget::openContextMenu);
|
||||
|
||||
connect(g_debugger_window, &DebuggerWindow::onVMActuallyPaused,
|
||||
this, &DisassemblyWidget::gotoProgramCounterOnPause);
|
||||
|
||||
receiveEvent<DebuggerEvents::Refresh>([this](const DebuggerEvents::Refresh& event) -> bool {
|
||||
update();
|
||||
return true;
|
||||
});
|
||||
|
||||
receiveEvent<DebuggerEvents::GoToAddress>([this](const DebuggerEvents::GoToAddress& event) -> bool {
|
||||
if (event.filter != DebuggerEvents::GoToAddress::NONE &&
|
||||
event.filter != DebuggerEvents::GoToAddress::DISASSEMBLER)
|
||||
return false;
|
||||
|
||||
gotoAddress(event.address, event.switch_to_tab);
|
||||
|
||||
if (event.switch_to_tab)
|
||||
switchToThisTab();
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
DisassemblyWidget::~DisassemblyWidget() = default;
|
||||
|
||||
void DisassemblyWidget::toJson(JsonValueWrapper& json)
|
||||
{
|
||||
DebuggerWidget::toJson(json);
|
||||
|
||||
json.value().AddMember("startAddress", m_visibleStart, json.allocator());
|
||||
json.value().AddMember("goToPCOnPause", m_goToProgramCounterOnPause, json.allocator());
|
||||
json.value().AddMember("showInstructionBytes", m_showInstructionBytes, json.allocator());
|
||||
}
|
||||
|
||||
bool DisassemblyWidget::fromJson(const JsonValueWrapper& json)
|
||||
{
|
||||
if (!DebuggerWidget::fromJson(json))
|
||||
return false;
|
||||
|
||||
auto start_address = json.value().FindMember("startAddress");
|
||||
if (start_address != json.value().MemberEnd() && start_address->value.IsUint())
|
||||
m_visibleStart = start_address->value.GetUint() & ~3;
|
||||
|
||||
auto go_to_pc_on_pause = json.value().FindMember("goToPCOnPause");
|
||||
if (go_to_pc_on_pause != json.value().MemberEnd() && go_to_pc_on_pause->value.IsBool())
|
||||
m_goToProgramCounterOnPause = go_to_pc_on_pause->value.GetBool();
|
||||
|
||||
auto show_instruction_bytes = json.value().FindMember("showInstructionBytes");
|
||||
if (show_instruction_bytes != json.value().MemberEnd() && show_instruction_bytes->value.IsBool())
|
||||
m_showInstructionBytes = show_instruction_bytes->value.GetBool();
|
||||
|
||||
repaint();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextCopyAddress()
|
||||
{
|
||||
QGuiApplication::clipboard()->setText(FetchSelectionInfo(SelectionInfo::ADDRESS));
|
||||
@@ -46,7 +108,7 @@ void DisassemblyWidget::contextCopyInstructionText()
|
||||
|
||||
void DisassemblyWidget::contextAssembleInstruction()
|
||||
{
|
||||
if (!m_cpu->isCpuPaused())
|
||||
if (!cpu().isCpuPaused())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Assemble Error"), tr("Unable to change assembly while core is running"));
|
||||
return;
|
||||
@@ -63,7 +125,7 @@ void DisassemblyWidget::contextAssembleInstruction()
|
||||
|
||||
u32 encodedInstruction;
|
||||
std::string errorText;
|
||||
bool valid = MipsAssembleOpcode(instruction.toLocal8Bit().constData(), m_cpu, m_selectedAddressStart, encodedInstruction, errorText);
|
||||
bool valid = MipsAssembleOpcode(instruction.toLocal8Bit().constData(), &cpu(), m_selectedAddressStart, encodedInstruction, errorText);
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
@@ -72,32 +134,32 @@ void DisassemblyWidget::contextAssembleInstruction()
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::RunOnCPUThread([this, start = m_selectedAddressStart, end = m_selectedAddressEnd, cpu = m_cpu, val = encodedInstruction] {
|
||||
Host::RunOnCPUThread([this, start = m_selectedAddressStart, end = m_selectedAddressEnd, cpu = &cpu(), val = encodedInstruction] {
|
||||
for (u32 i = start; i <= end; i += 4)
|
||||
{
|
||||
this->m_nopedInstructions.insert({i, cpu->read32(i)});
|
||||
cpu->write32(i, val);
|
||||
}
|
||||
emit VMUpdate();
|
||||
DebuggerWidget::broadcastEvent(DebuggerEvents::VMUpdate());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextNoopInstruction()
|
||||
{
|
||||
Host::RunOnCPUThread([this, start = m_selectedAddressStart, end = m_selectedAddressEnd, cpu = m_cpu] {
|
||||
Host::RunOnCPUThread([this, start = m_selectedAddressStart, end = m_selectedAddressEnd, cpu = &cpu()] {
|
||||
for (u32 i = start; i <= end; i += 4)
|
||||
{
|
||||
this->m_nopedInstructions.insert({i, cpu->read32(i)});
|
||||
cpu->write32(i, 0x00);
|
||||
}
|
||||
emit VMUpdate();
|
||||
DebuggerWidget::broadcastEvent(DebuggerEvents::VMUpdate());
|
||||
});
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextRestoreInstruction()
|
||||
{
|
||||
Host::RunOnCPUThread([this, start = m_selectedAddressStart, end = m_selectedAddressEnd, cpu = m_cpu] {
|
||||
Host::RunOnCPUThread([this, start = m_selectedAddressStart, end = m_selectedAddressEnd, cpu = &cpu()] {
|
||||
for (u32 i = start; i <= end; i += 4)
|
||||
{
|
||||
if (this->m_nopedInstructions.find(i) != this->m_nopedInstructions.end())
|
||||
@@ -106,14 +168,14 @@ void DisassemblyWidget::contextRestoreInstruction()
|
||||
this->m_nopedInstructions.erase(i);
|
||||
}
|
||||
}
|
||||
emit VMUpdate();
|
||||
DebuggerWidget::broadcastEvent(DebuggerEvents::VMUpdate());
|
||||
});
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextRunToCursor()
|
||||
{
|
||||
const u32 selectedAddressStart = m_selectedAddressStart;
|
||||
Host::RunOnCPUThread([cpu = m_cpu, selectedAddressStart] {
|
||||
Host::RunOnCPUThread([cpu = &cpu(), selectedAddressStart] {
|
||||
CBreakPoints::AddBreakPoint(cpu->getCpuType(), selectedAddressStart, true);
|
||||
cpu->resumeCpu();
|
||||
});
|
||||
@@ -121,28 +183,13 @@ void DisassemblyWidget::contextRunToCursor()
|
||||
|
||||
void DisassemblyWidget::contextJumpToCursor()
|
||||
{
|
||||
m_cpu->setPc(m_selectedAddressStart);
|
||||
cpu().setPc(m_selectedAddressStart);
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextToggleBreakpoint()
|
||||
{
|
||||
if (!m_cpu->isAlive())
|
||||
return;
|
||||
|
||||
const u32 selectedAddressStart = m_selectedAddressStart;
|
||||
const BreakPointCpu cpuType = m_cpu->getCpuType();
|
||||
if (CBreakPoints::IsAddressBreakPoint(cpuType, selectedAddressStart))
|
||||
{
|
||||
Host::RunOnCPUThread([cpuType, selectedAddressStart] { CBreakPoints::RemoveBreakPoint(cpuType, selectedAddressStart); });
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::RunOnCPUThread([cpuType, selectedAddressStart] { CBreakPoints::AddBreakPoint(cpuType, selectedAddressStart); });
|
||||
}
|
||||
|
||||
breakpointsChanged();
|
||||
this->repaint();
|
||||
toggleBreakpoint(m_selectedAddressStart);
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextFollowBranch()
|
||||
@@ -171,7 +218,7 @@ void DisassemblyWidget::contextGoToAddress()
|
||||
|
||||
u64 address = 0;
|
||||
std::string error;
|
||||
if (!m_cpu->evaluateExpression(targetString.toStdString().c_str(), address, error))
|
||||
if (!cpu().evaluateExpression(targetString.toStdString().c_str(), address, error))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Cannot Go To"), QString::fromStdString(error));
|
||||
return;
|
||||
@@ -182,7 +229,8 @@ void DisassemblyWidget::contextGoToAddress()
|
||||
|
||||
void DisassemblyWidget::contextAddFunction()
|
||||
{
|
||||
NewFunctionDialog* dialog = new NewFunctionDialog(*m_cpu, this);
|
||||
NewFunctionDialog* dialog = new NewFunctionDialog(cpu(), this);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dialog->setName(QString("func_%1").arg(m_selectedAddressStart, 8, 16, QChar('0')));
|
||||
dialog->setAddress(m_selectedAddressStart);
|
||||
if (m_selectedAddressEnd != m_selectedAddressStart)
|
||||
@@ -193,13 +241,13 @@ void DisassemblyWidget::contextAddFunction()
|
||||
|
||||
void DisassemblyWidget::contextCopyFunctionName()
|
||||
{
|
||||
std::string name = m_cpu->GetSymbolGuardian().FunctionStartingAtAddress(m_selectedAddressStart).name;
|
||||
std::string name = cpu().GetSymbolGuardian().FunctionStartingAtAddress(m_selectedAddressStart).name;
|
||||
QGuiApplication::clipboard()->setText(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextRemoveFunction()
|
||||
{
|
||||
m_cpu->GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||
cpu().GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||
ccc::Function* curFunc = database.functions.symbol_overlapping_address(m_selectedAddressStart);
|
||||
if (!curFunc)
|
||||
return;
|
||||
@@ -215,7 +263,7 @@ void DisassemblyWidget::contextRemoveFunction()
|
||||
|
||||
void DisassemblyWidget::contextRenameFunction()
|
||||
{
|
||||
const FunctionInfo curFunc = m_cpu->GetSymbolGuardian().FunctionOverlappingAddress(m_selectedAddressStart);
|
||||
const FunctionInfo curFunc = cpu().GetSymbolGuardian().FunctionOverlappingAddress(m_selectedAddressStart);
|
||||
|
||||
if (!curFunc.address.valid())
|
||||
{
|
||||
@@ -236,28 +284,28 @@ void DisassemblyWidget::contextRenameFunction()
|
||||
return;
|
||||
}
|
||||
|
||||
m_cpu->GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||
cpu().GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||
database.functions.rename_symbol(curFunc.handle, newName.toStdString());
|
||||
});
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextStubFunction()
|
||||
{
|
||||
FunctionInfo function = m_cpu->GetSymbolGuardian().FunctionOverlappingAddress(m_selectedAddressStart);
|
||||
FunctionInfo function = cpu().GetSymbolGuardian().FunctionOverlappingAddress(m_selectedAddressStart);
|
||||
u32 address = function.address.valid() ? function.address.value : m_selectedAddressStart;
|
||||
|
||||
Host::RunOnCPUThread([this, address, cpu = m_cpu] {
|
||||
Host::RunOnCPUThread([this, address, cpu = &cpu()] {
|
||||
this->m_stubbedFunctions.insert({address, {cpu->read32(address), cpu->read32(address + 4)}});
|
||||
cpu->write32(address, 0x03E00008); // jr ra
|
||||
cpu->write32(address + 4, 0x00000000); // nop
|
||||
emit VMUpdate();
|
||||
DebuggerWidget::broadcastEvent(DebuggerEvents::VMUpdate());
|
||||
});
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextRestoreFunction()
|
||||
{
|
||||
u32 address = m_selectedAddressStart;
|
||||
m_cpu->GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
||||
cpu().GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
||||
const ccc::Function* function = database.functions.symbol_overlapping_address(m_selectedAddressStart);
|
||||
if (function)
|
||||
address = function->address().value;
|
||||
@@ -266,12 +314,12 @@ void DisassemblyWidget::contextRestoreFunction()
|
||||
auto stub = m_stubbedFunctions.find(address);
|
||||
if (stub != m_stubbedFunctions.end())
|
||||
{
|
||||
Host::RunOnCPUThread([this, address, cpu = m_cpu, stub] {
|
||||
Host::RunOnCPUThread([this, address, cpu = &cpu(), stub] {
|
||||
auto [first_instruction, second_instruction] = stub->second;
|
||||
cpu->write32(address, first_instruction);
|
||||
cpu->write32(address + 4, second_instruction);
|
||||
this->m_stubbedFunctions.erase(address);
|
||||
emit VMUpdate();
|
||||
DebuggerWidget::broadcastEvent(DebuggerEvents::VMUpdate());
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -280,18 +328,12 @@ void DisassemblyWidget::contextRestoreFunction()
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextShowOpcode()
|
||||
void DisassemblyWidget::contextShowInstructionBytes()
|
||||
{
|
||||
m_showInstructionOpcode = !m_showInstructionOpcode;
|
||||
m_showInstructionBytes = !m_showInstructionBytes;
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::SetCpu(DebugInterface* cpu)
|
||||
{
|
||||
m_cpu = cpu;
|
||||
m_disassemblyManager.setCpu(cpu);
|
||||
}
|
||||
|
||||
QString DisassemblyWidget::GetLineDisasm(u32 address)
|
||||
{
|
||||
DisassemblyLineInfo lineInfo;
|
||||
@@ -322,7 +364,7 @@ void DisassemblyWidget::paintEvent(QPaintEvent* event)
|
||||
bool inSelectionBlock = false;
|
||||
bool alternate = m_visibleStart % 8;
|
||||
|
||||
const u32 curPC = m_cpu->getPC(); // Get the PC here, because it'll change when we are drawing and make it seem like there are two PCs
|
||||
const u32 curPC = cpu().getPC(); // Get the PC here, because it'll change when we are drawing and make it seem like there are two PCs
|
||||
|
||||
for (u32 i = 0; i <= m_visibleRows; i++)
|
||||
{
|
||||
@@ -347,7 +389,7 @@ void DisassemblyWidget::paintEvent(QPaintEvent* event)
|
||||
|
||||
// Breakpoint marker
|
||||
bool enabled;
|
||||
if (CBreakPoints::IsAddressBreakPoint(m_cpu->getCpuType(), rowAddress, &enabled) && !CBreakPoints::IsTempBreakPoint(m_cpu->getCpuType(), rowAddress))
|
||||
if (CBreakPoints::IsAddressBreakPoint(cpu().getCpuType(), rowAddress, &enabled) && !CBreakPoints::IsTempBreakPoint(cpu().getCpuType(), rowAddress))
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
@@ -371,7 +413,7 @@ void DisassemblyWidget::paintEvent(QPaintEvent* event)
|
||||
s32 branchCount = 0;
|
||||
for (const auto& branchLine : branchLines)
|
||||
{
|
||||
if (branchCount == (m_showInstructionOpcode ? 3 : 5))
|
||||
if (branchCount == (m_showInstructionBytes ? 3 : 5))
|
||||
break;
|
||||
const int winBottom = this->height();
|
||||
|
||||
@@ -506,21 +548,7 @@ void DisassemblyWidget::mousePressEvent(QMouseEvent* event)
|
||||
|
||||
void DisassemblyWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
if (!m_cpu->isAlive())
|
||||
return;
|
||||
|
||||
const u32 selectedAddress = (static_cast<int>(event->position().y()) / m_rowHeight * 4) + m_visibleStart;
|
||||
const BreakPointCpu cpuType = m_cpu->getCpuType();
|
||||
if (CBreakPoints::IsAddressBreakPoint(cpuType, selectedAddress))
|
||||
{
|
||||
Host::RunOnCPUThread([cpuType, selectedAddress] { CBreakPoints::RemoveBreakPoint(cpuType, selectedAddress); });
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::RunOnCPUThread([cpuType, selectedAddress] { CBreakPoints::AddBreakPoint(cpuType, selectedAddress); });
|
||||
}
|
||||
breakpointsChanged();
|
||||
this->repaint();
|
||||
toggleBreakpoint((static_cast<int>(event->position().y()) / m_rowHeight * 4) + m_visibleStart);
|
||||
}
|
||||
|
||||
void DisassemblyWidget::wheelEvent(QWheelEvent* event)
|
||||
@@ -598,115 +626,139 @@ void DisassemblyWidget::keyPressEvent(QKeyEvent* event)
|
||||
contextFollowBranch();
|
||||
break;
|
||||
case Qt::Key_Left:
|
||||
gotoAddressAndSetFocus(m_cpu->getPC());
|
||||
gotoAddressAndSetFocus(cpu().getPC());
|
||||
break;
|
||||
case Qt::Key_O:
|
||||
m_showInstructionOpcode = !m_showInstructionOpcode;
|
||||
case Qt::Key_I:
|
||||
m_showInstructionBytes = !m_showInstructionBytes;
|
||||
break;
|
||||
}
|
||||
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::customMenuRequested(QPoint pos)
|
||||
void DisassemblyWidget::openContextMenu(QPoint pos)
|
||||
{
|
||||
if (!m_cpu->isAlive())
|
||||
if (!cpu().isAlive())
|
||||
return;
|
||||
|
||||
QMenu* contextMenu = new QMenu(this);
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QAction* action = 0;
|
||||
contextMenu->addAction(action = new QAction(tr("Copy Address"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextCopyAddress);
|
||||
contextMenu->addAction(action = new QAction(tr("Copy Instruction Hex"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextCopyInstructionHex);
|
||||
contextMenu->addAction(action = new QAction(tr("&Copy Instruction Text"), this));
|
||||
action->setShortcut(QKeySequence(Qt::Key_C));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextCopyInstructionText);
|
||||
if (m_cpu->GetSymbolGuardian().FunctionExistsWithStartingAddress(m_selectedAddressStart))
|
||||
QAction* copy_address_action = menu->addAction(tr("Copy Address"));
|
||||
connect(copy_address_action, &QAction::triggered, this, &DisassemblyWidget::contextCopyAddress);
|
||||
|
||||
QAction* copy_instruction_hex_action = menu->addAction(tr("Copy Instruction Hex"));
|
||||
connect(copy_instruction_hex_action, &QAction::triggered, this, &DisassemblyWidget::contextCopyInstructionHex);
|
||||
|
||||
QAction* copy_instruction_text_action = menu->addAction(tr("&Copy Instruction Text"));
|
||||
copy_instruction_text_action->setShortcut(QKeySequence(Qt::Key_C));
|
||||
connect(copy_instruction_text_action, &QAction::triggered, this, &DisassemblyWidget::contextCopyInstructionText);
|
||||
|
||||
if (cpu().GetSymbolGuardian().FunctionExistsWithStartingAddress(m_selectedAddressStart))
|
||||
{
|
||||
contextMenu->addAction(action = new QAction(tr("Copy Function Name"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextCopyFunctionName);
|
||||
QAction* copy_function_name_action = menu->addAction(tr("Copy Function Name"));
|
||||
connect(copy_function_name_action, &QAction::triggered, this, &DisassemblyWidget::contextCopyFunctionName);
|
||||
}
|
||||
contextMenu->addSeparator();
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
if (AddressCanRestore(m_selectedAddressStart, m_selectedAddressEnd))
|
||||
{
|
||||
contextMenu->addAction(action = new QAction(tr("Restore Instruction(s)"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextRestoreInstruction);
|
||||
QAction* restore_instruction_action = menu->addAction(tr("Restore Instruction(s)"));
|
||||
connect(restore_instruction_action, &QAction::triggered, this, &DisassemblyWidget::contextRestoreInstruction);
|
||||
}
|
||||
contextMenu->addAction(action = new QAction(tr("Asse&mble new Instruction(s)"), this));
|
||||
action->setShortcut(QKeySequence(Qt::Key_M));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextAssembleInstruction);
|
||||
contextMenu->addAction(action = new QAction(tr("NOP Instruction(s)"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextNoopInstruction);
|
||||
contextMenu->addSeparator();
|
||||
contextMenu->addAction(action = new QAction(tr("Run to Cursor"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextRunToCursor);
|
||||
contextMenu->addAction(action = new QAction(tr("&Jump to Cursor"), this));
|
||||
action->setShortcut(QKeySequence(Qt::Key_J));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextJumpToCursor);
|
||||
contextMenu->addAction(action = new QAction(tr("Toggle &Breakpoint"), this));
|
||||
action->setShortcut(QKeySequence(Qt::Key_B));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextToggleBreakpoint);
|
||||
contextMenu->addAction(action = new QAction(tr("Follow Branch"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextFollowBranch);
|
||||
contextMenu->addSeparator();
|
||||
contextMenu->addAction(action = new QAction(tr("&Go to Address"), this));
|
||||
action->setShortcut(QKeySequence(Qt::Key_G));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextGoToAddress);
|
||||
contextMenu->addAction(action = new QAction(tr("Go to in Memory View"), this));
|
||||
connect(action, &QAction::triggered, this, [this]() { gotoInMemory(m_selectedAddressStart); });
|
||||
|
||||
contextMenu->addAction(action = new QAction(tr("Go to PC on Pause"), this));
|
||||
action->setCheckable(true);
|
||||
action->setChecked(m_goToProgramCounterOnPause);
|
||||
connect(action, &QAction::triggered, this, [this](bool value) { m_goToProgramCounterOnPause = value; });
|
||||
QAction* assemble_new_instruction = menu->addAction(tr("Asse&mble new Instruction(s)"));
|
||||
assemble_new_instruction->setShortcut(QKeySequence(Qt::Key_M));
|
||||
connect(assemble_new_instruction, &QAction::triggered, this, &DisassemblyWidget::contextAssembleInstruction);
|
||||
|
||||
QAction* nop_instruction_action = menu->addAction(tr("NOP Instruction(s)"));
|
||||
connect(nop_instruction_action, &QAction::triggered, this, &DisassemblyWidget::contextNoopInstruction);
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
QAction* run_to_cursor_action = menu->addAction(tr("Run to Cursor"));
|
||||
connect(run_to_cursor_action, &QAction::triggered, this, &DisassemblyWidget::contextRunToCursor);
|
||||
|
||||
QAction* jump_to_cursor_action = menu->addAction(tr("&Jump to Cursor"));
|
||||
jump_to_cursor_action->setShortcut(QKeySequence(Qt::Key_J));
|
||||
connect(jump_to_cursor_action, &QAction::triggered, this, &DisassemblyWidget::contextJumpToCursor);
|
||||
|
||||
QAction* toggle_breakpoint_action = menu->addAction(tr("Toggle &Breakpoint"));
|
||||
toggle_breakpoint_action->setShortcut(QKeySequence(Qt::Key_B));
|
||||
connect(toggle_breakpoint_action, &QAction::triggered, this, &DisassemblyWidget::contextToggleBreakpoint);
|
||||
|
||||
QAction* follow_branch_action = menu->addAction(tr("Follow Branch"));
|
||||
connect(follow_branch_action, &QAction::triggered, this, &DisassemblyWidget::contextFollowBranch);
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
QAction* go_to_address_action = menu->addAction(tr("&Go to Address"));
|
||||
go_to_address_action->setShortcut(QKeySequence(Qt::Key_G));
|
||||
connect(go_to_address_action, &QAction::triggered, this, &DisassemblyWidget::contextGoToAddress);
|
||||
|
||||
createEventActions<DebuggerEvents::GoToAddress>(menu, [this]() {
|
||||
DebuggerEvents::GoToAddress event;
|
||||
event.address = m_selectedAddressStart;
|
||||
return std::optional(event);
|
||||
});
|
||||
|
||||
QAction* go_to_pc_on_pause = menu->addAction(tr("Go to PC on Pause"));
|
||||
go_to_pc_on_pause->setCheckable(true);
|
||||
go_to_pc_on_pause->setChecked(m_goToProgramCounterOnPause);
|
||||
connect(go_to_pc_on_pause, &QAction::triggered, this,
|
||||
[this](bool value) { m_goToProgramCounterOnPause = value; });
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
QAction* add_function_action = menu->addAction(tr("Add Function"));
|
||||
connect(add_function_action, &QAction::triggered, this, &DisassemblyWidget::contextAddFunction);
|
||||
|
||||
QAction* rename_function_action = menu->addAction(tr("Rename Function"));
|
||||
connect(rename_function_action, &QAction::triggered, this, &DisassemblyWidget::contextRenameFunction);
|
||||
|
||||
QAction* remove_function_action = menu->addAction(tr("Remove Function"));
|
||||
menu->addAction(remove_function_action);
|
||||
connect(remove_function_action, &QAction::triggered, this, &DisassemblyWidget::contextRemoveFunction);
|
||||
|
||||
contextMenu->addSeparator();
|
||||
contextMenu->addAction(action = new QAction(tr("Add Function"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextAddFunction);
|
||||
contextMenu->addAction(action = new QAction(tr("Rename Function"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextRenameFunction);
|
||||
contextMenu->addAction(action = new QAction(tr("Remove Function"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextRemoveFunction);
|
||||
if (FunctionCanRestore(m_selectedAddressStart))
|
||||
{
|
||||
contextMenu->addAction(action = new QAction(tr("Restore Function"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextRestoreFunction);
|
||||
QAction* restore_action = menu->addAction(tr("Restore Function"));
|
||||
connect(restore_action, &QAction::triggered, this, &DisassemblyWidget::contextRestoreFunction);
|
||||
}
|
||||
else
|
||||
{
|
||||
contextMenu->addAction(action = new QAction(tr("Stub (NOP) Function"), this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextStubFunction);
|
||||
QAction* stub_action = menu->addAction(tr("Stub (NOP) Function"));
|
||||
connect(stub_action, &QAction::triggered, this, &DisassemblyWidget::contextStubFunction);
|
||||
}
|
||||
|
||||
contextMenu->addSeparator();
|
||||
contextMenu->addAction(action = new QAction(tr("Show &Opcode"), this));
|
||||
action->setShortcut(QKeySequence(Qt::Key_O));
|
||||
action->setCheckable(true);
|
||||
action->setChecked(m_showInstructionOpcode);
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextShowOpcode);
|
||||
menu->addSeparator();
|
||||
|
||||
contextMenu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
contextMenu->popup(this->mapToGlobal(pos));
|
||||
QAction* show_instruction_bytes_action = menu->addAction(tr("Show &Instruction Bytes"));
|
||||
show_instruction_bytes_action->setShortcut(QKeySequence(Qt::Key_I));
|
||||
show_instruction_bytes_action->setCheckable(true);
|
||||
show_instruction_bytes_action->setChecked(m_showInstructionBytes);
|
||||
connect(show_instruction_bytes_action, &QAction::triggered, this, &DisassemblyWidget::contextShowInstructionBytes);
|
||||
|
||||
menu->popup(this->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
inline QString DisassemblyWidget::DisassemblyStringFromAddress(u32 address, QFont font, u32 pc, bool selected)
|
||||
{
|
||||
DisassemblyLineInfo line;
|
||||
|
||||
if (!m_cpu->isValidAddress(address))
|
||||
if (!cpu().isValidAddress(address))
|
||||
return tr("%1 NOT VALID ADDRESS").arg(address, 8, 16, QChar('0')).toUpper();
|
||||
// Todo? support non symbol view?
|
||||
m_disassemblyManager.getLine(address, true, line);
|
||||
|
||||
const bool isConditional = line.info.isConditional && m_cpu->getPC() == address;
|
||||
const bool isConditional = line.info.isConditional && cpu().getPC() == address;
|
||||
const bool isConditionalMet = line.info.conditionMet;
|
||||
const bool isCurrentPC = m_cpu->getPC() == address;
|
||||
const bool isCurrentPC = cpu().getPC() == address;
|
||||
|
||||
FunctionInfo function = m_cpu->GetSymbolGuardian().FunctionStartingAtAddress(address);
|
||||
SymbolInfo symbol = m_cpu->GetSymbolGuardian().SymbolStartingAtAddress(address);
|
||||
const bool showOpcode = m_showInstructionOpcode && m_cpu->isAlive();
|
||||
FunctionInfo function = cpu().GetSymbolGuardian().FunctionStartingAtAddress(address);
|
||||
SymbolInfo symbol = cpu().GetSymbolGuardian().SymbolStartingAtAddress(address);
|
||||
const bool showOpcode = m_showInstructionBytes && cpu().isAlive();
|
||||
|
||||
QString lineString;
|
||||
if (showOpcode)
|
||||
@@ -739,7 +791,7 @@ inline QString DisassemblyWidget::DisassemblyStringFromAddress(u32 address, QFon
|
||||
|
||||
if (showOpcode)
|
||||
{
|
||||
const u32 opcode = m_cpu->read32(address);
|
||||
const u32 opcode = cpu().read32(address);
|
||||
lineString = lineString.arg(QtUtils::FilledQStringFromValue(opcode, 16));
|
||||
}
|
||||
|
||||
@@ -754,16 +806,8 @@ inline QString DisassemblyWidget::DisassemblyStringFromAddress(u32 address, QFon
|
||||
|
||||
QColor DisassemblyWidget::GetAddressFunctionColor(u32 address)
|
||||
{
|
||||
// This is an attempt to figure out if the current palette is dark or light
|
||||
// We calculate the luminance of the alternateBase colour
|
||||
// and swap between our darker and lighter function colours
|
||||
|
||||
std::array<QColor, 6> colors;
|
||||
const QColor base = this->palette().alternateBase().color();
|
||||
|
||||
const auto Y = (base.redF() * 0.33) + (0.5 * base.greenF()) + (0.16 * base.blueF());
|
||||
|
||||
if (Y > 0.5)
|
||||
if (QtUtils::IsLightTheme(palette()))
|
||||
{
|
||||
colors = {
|
||||
QColor::fromRgba(0xFFFA3434),
|
||||
@@ -789,7 +833,7 @@ QColor DisassemblyWidget::GetAddressFunctionColor(u32 address)
|
||||
// Use the address to pick the colour since the value of the handle may
|
||||
// change from run to run.
|
||||
ccc::Address function_address =
|
||||
m_cpu->GetSymbolGuardian().FunctionOverlappingAddress(address).address;
|
||||
cpu().GetSymbolGuardian().FunctionOverlappingAddress(address).address;
|
||||
if (!function_address.valid())
|
||||
return palette().text().color();
|
||||
|
||||
@@ -817,7 +861,7 @@ QString DisassemblyWidget::FetchSelectionInfo(SelectionInfo selInfo)
|
||||
}
|
||||
else // INSTRUCTIONHEX
|
||||
{
|
||||
infoBlock += FilledQStringFromValue(m_cpu->read32(i), 16);
|
||||
infoBlock += FilledQStringFromValue(cpu().read32(i), 16);
|
||||
}
|
||||
}
|
||||
return infoBlock;
|
||||
@@ -831,7 +875,7 @@ void DisassemblyWidget::gotoAddressAndSetFocus(u32 address)
|
||||
void DisassemblyWidget::gotoProgramCounterOnPause()
|
||||
{
|
||||
if (m_goToProgramCounterOnPause)
|
||||
gotoAddress(m_cpu->getPC(), false);
|
||||
gotoAddress(cpu().getPC(), false);
|
||||
}
|
||||
|
||||
void DisassemblyWidget::gotoAddress(u32 address, bool should_set_focus)
|
||||
@@ -847,6 +891,27 @@ void DisassemblyWidget::gotoAddress(u32 address, bool should_set_focus)
|
||||
this->setFocus();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::toggleBreakpoint(u32 address)
|
||||
{
|
||||
if (!cpu().isAlive())
|
||||
return;
|
||||
|
||||
QPointer<DisassemblyWidget> disassembly_widget(this);
|
||||
|
||||
Host::RunOnCPUThread([cpu = &cpu(), address, disassembly_widget] {
|
||||
if (!CBreakPoints::IsAddressBreakPoint(cpu->getCpuType(), address))
|
||||
CBreakPoints::AddBreakPoint(cpu->getCpuType(), address);
|
||||
else
|
||||
CBreakPoints::RemoveBreakPoint(cpu->getCpuType(), address);
|
||||
|
||||
QtHost::RunOnUIThread([cpu, disassembly_widget]() {
|
||||
BreakpointModel::getInstance(*cpu)->refreshData();
|
||||
if (disassembly_widget)
|
||||
disassembly_widget->repaint();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bool DisassemblyWidget::AddressCanRestore(u32 start, u32 end)
|
||||
{
|
||||
for (u32 i = start; i <= end; i += 4)
|
||||
@@ -861,7 +926,7 @@ bool DisassemblyWidget::AddressCanRestore(u32 start, u32 end)
|
||||
|
||||
bool DisassemblyWidget::FunctionCanRestore(u32 address)
|
||||
{
|
||||
FunctionInfo function = m_cpu->GetSymbolGuardian().FunctionOverlappingAddress(address);
|
||||
FunctionInfo function = cpu().GetSymbolGuardian().FunctionOverlappingAddress(address);
|
||||
if (function.address.valid())
|
||||
address = function.address.value;
|
||||
|
||||
|
||||
@@ -5,36 +5,36 @@
|
||||
|
||||
#include "ui_DisassemblyWidget.h"
|
||||
|
||||
#include "pcsx2/DebugTools/DebugInterface.h"
|
||||
#include "DebuggerWidget.h"
|
||||
|
||||
#include "pcsx2/DebugTools/DisassemblyManager.h"
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
class DisassemblyWidget final : public QWidget
|
||||
class DisassemblyWidget final : public DebuggerWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DisassemblyWidget(QWidget* parent);
|
||||
DisassemblyWidget(const DebuggerWidgetParameters& parameters);
|
||||
~DisassemblyWidget();
|
||||
|
||||
// Required because our constructor needs to take no extra arguments.
|
||||
void SetCpu(DebugInterface* cpu);
|
||||
void toJson(JsonValueWrapper& json) override;
|
||||
bool fromJson(const JsonValueWrapper& json) override;
|
||||
|
||||
// Required for the breakpoint list (ugh wtf)
|
||||
QString GetLineDisasm(u32 address);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event);
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
void wheelEvent(QWheelEvent* event);
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||
void wheelEvent(QWheelEvent* event) override;
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
|
||||
public slots:
|
||||
void customMenuRequested(QPoint pos);
|
||||
void openContextMenu(QPoint pos);
|
||||
|
||||
// Context menu actions
|
||||
// When called, m_selectedAddressStart will be the 'selected' instruction
|
||||
@@ -56,23 +56,18 @@ public slots:
|
||||
void contextRemoveFunction();
|
||||
void contextStubFunction();
|
||||
void contextRestoreFunction();
|
||||
void contextShowOpcode();
|
||||
void contextShowInstructionBytes();
|
||||
|
||||
void gotoAddressAndSetFocus(u32 address);
|
||||
void gotoProgramCounterOnPause();
|
||||
void gotoAddress(u32 address, bool should_set_focus);
|
||||
|
||||
void setDemangle(bool demangle) { m_demangleFunctions = demangle; };
|
||||
signals:
|
||||
void gotoInMemory(u32 address);
|
||||
void breakpointsChanged();
|
||||
void VMUpdate();
|
||||
void toggleBreakpoint(u32 address);
|
||||
|
||||
private:
|
||||
Ui::DisassemblyWidget ui;
|
||||
Ui::DisassemblyWidget m_ui;
|
||||
|
||||
DebugInterface* m_cpu;
|
||||
u32 m_visibleStart = 0x00336318; // The address of the first opcode shown(row 0)
|
||||
u32 m_visibleStart = 0x100000; // The address of the first instruction shown.
|
||||
u32 m_visibleRows;
|
||||
u32 m_selectedAddressStart = 0;
|
||||
u32 m_selectedAddressEnd = 0;
|
||||
@@ -81,8 +76,7 @@ private:
|
||||
std::map<u32, u32> m_nopedInstructions;
|
||||
std::map<u32, std::tuple<u32, u32>> m_stubbedFunctions;
|
||||
|
||||
bool m_demangleFunctions = true;
|
||||
bool m_showInstructionOpcode = true;
|
||||
bool m_showInstructionBytes = true;
|
||||
bool m_goToProgramCounterOnPause = true;
|
||||
DisassemblyManager m_disassemblyManager;
|
||||
|
||||
|
||||
918
pcsx2-qt/Debugger/Docking/DockLayout.cpp
Normal file
918
pcsx2-qt/Debugger/Docking/DockLayout.cpp
Normal file
@@ -0,0 +1,918 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "DockLayout.h"
|
||||
|
||||
#include "Debugger/DebuggerWidget.h"
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
#include "Debugger/JsonValueWrapper.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
|
||||
#include <kddockwidgets/Config.h>
|
||||
#include <kddockwidgets/DockWidget.h>
|
||||
#include <kddockwidgets/LayoutSaver.h>
|
||||
#include <kddockwidgets/core/DockRegistry.h>
|
||||
#include <kddockwidgets/core/DockWidget.h>
|
||||
#include <kddockwidgets/core/Group.h>
|
||||
#include <kddockwidgets/core/Layout.h>
|
||||
#include <kddockwidgets/core/ViewFactory.h>
|
||||
#include <kddockwidgets/qtwidgets/Group.h>
|
||||
#include <kddockwidgets/qtwidgets/MainWindow.h>
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
|
||||
const char* DEBUGGER_LAYOUT_FILE_FORMAT = "PCSX2 Debugger User Interface Layout";
|
||||
|
||||
// Increment this whenever there is a breaking change to the JSON format.
|
||||
const u32 DEBUGGER_LAYOUT_FILE_VERSION_MAJOR = 1;
|
||||
|
||||
// Increment this whenever there is a non-breaking change to the JSON format.
|
||||
const u32 DEBUGGER_LAYOUT_FILE_VERSION_MINOR = 0;
|
||||
|
||||
DockLayout::DockLayout(
|
||||
QString name,
|
||||
BreakPointCpu cpu,
|
||||
bool is_default,
|
||||
const std::string& base_name,
|
||||
DockLayout::Index index)
|
||||
: m_name(name)
|
||||
, m_cpu(cpu)
|
||||
, m_is_default(is_default)
|
||||
, m_base_layout(base_name)
|
||||
{
|
||||
reset();
|
||||
save(index);
|
||||
}
|
||||
|
||||
DockLayout::DockLayout(
|
||||
QString name,
|
||||
BreakPointCpu cpu,
|
||||
bool is_default,
|
||||
DockLayout::Index index)
|
||||
: m_name(name)
|
||||
, m_cpu(cpu)
|
||||
, m_is_default(is_default)
|
||||
{
|
||||
save(index);
|
||||
}
|
||||
|
||||
DockLayout::DockLayout(
|
||||
QString name,
|
||||
BreakPointCpu cpu,
|
||||
bool is_default,
|
||||
const DockLayout& layout_to_clone,
|
||||
DockLayout::Index index)
|
||||
: m_name(name)
|
||||
, m_cpu(cpu)
|
||||
, m_is_default(is_default)
|
||||
, m_next_unique_name(layout_to_clone.m_next_unique_name)
|
||||
, m_base_layout(layout_to_clone.m_base_layout)
|
||||
, m_toolbars(layout_to_clone.m_toolbars)
|
||||
, m_geometry(layout_to_clone.m_geometry)
|
||||
{
|
||||
for (const auto& [unique_name, widget_to_clone] : layout_to_clone.m_widgets)
|
||||
{
|
||||
auto widget_description = DockTables::DEBUGGER_WIDGETS.find(widget_to_clone->metaObject()->className());
|
||||
if (widget_description == DockTables::DEBUGGER_WIDGETS.end())
|
||||
continue;
|
||||
|
||||
DebuggerWidgetParameters parameters;
|
||||
parameters.unique_name = unique_name;
|
||||
parameters.cpu = &DebugInterface::get(cpu);
|
||||
parameters.cpu_override = widget_to_clone->cpuOverride();
|
||||
|
||||
DebuggerWidget* new_widget = widget_description->second.create_widget(parameters);
|
||||
new_widget->setCustomDisplayName(widget_to_clone->customDisplayName());
|
||||
new_widget->setPrimary(widget_to_clone->isPrimary());
|
||||
m_widgets.emplace(unique_name, new_widget);
|
||||
}
|
||||
|
||||
save(index);
|
||||
}
|
||||
|
||||
DockLayout::DockLayout(
|
||||
const std::string& path,
|
||||
DockLayout::LoadResult& result,
|
||||
DockLayout::Index& index_last_session,
|
||||
DockLayout::Index index)
|
||||
{
|
||||
load(path, result, index_last_session);
|
||||
}
|
||||
|
||||
DockLayout::~DockLayout()
|
||||
{
|
||||
for (auto& [unique_name, widget] : m_widgets)
|
||||
{
|
||||
pxAssert(widget.get());
|
||||
|
||||
delete widget;
|
||||
}
|
||||
}
|
||||
|
||||
const QString& DockLayout::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void DockLayout::setName(QString name)
|
||||
{
|
||||
m_name = std::move(name);
|
||||
}
|
||||
|
||||
BreakPointCpu DockLayout::cpu() const
|
||||
{
|
||||
return m_cpu;
|
||||
}
|
||||
|
||||
bool DockLayout::isDefault() const
|
||||
{
|
||||
return m_is_default;
|
||||
}
|
||||
|
||||
void DockLayout::setCpu(BreakPointCpu cpu)
|
||||
{
|
||||
m_cpu = cpu;
|
||||
|
||||
for (auto& [unique_name, widget] : m_widgets)
|
||||
{
|
||||
pxAssert(widget.get());
|
||||
|
||||
if (!widget->setCpu(DebugInterface::get(cpu)))
|
||||
recreateDebuggerWidget(unique_name);
|
||||
}
|
||||
}
|
||||
|
||||
void DockLayout::freeze()
|
||||
{
|
||||
pxAssert(m_is_active);
|
||||
m_is_active = false;
|
||||
|
||||
if (g_debugger_window)
|
||||
m_toolbars = g_debugger_window->saveState();
|
||||
|
||||
// Store the geometry of all the dock widgets as JSON.
|
||||
KDDockWidgets::LayoutSaver saver(KDDockWidgets::RestoreOption_RelativeToMainWindow);
|
||||
m_geometry = saver.serializeLayout();
|
||||
|
||||
// Delete the dock widgets.
|
||||
for (KDDockWidgets::Core::DockWidget* dock : KDDockWidgets::DockRegistry::self()->dockwidgets())
|
||||
{
|
||||
// Make sure the dock widget releases ownership of its content.
|
||||
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(dock->view());
|
||||
view->setWidget(new QWidget());
|
||||
|
||||
delete dock;
|
||||
}
|
||||
}
|
||||
|
||||
void DockLayout::thaw()
|
||||
{
|
||||
pxAssert(!m_is_active);
|
||||
m_is_active = true;
|
||||
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
// Restore the state of the toolbars.
|
||||
if (m_toolbars.isEmpty())
|
||||
{
|
||||
const DockTables::DefaultDockLayout* base_layout = DockTables::defaultLayout(m_base_layout);
|
||||
if (base_layout)
|
||||
{
|
||||
for (QToolBar* toolbar : g_debugger_window->findChildren<QToolBar*>())
|
||||
if (base_layout->toolbars.contains(toolbar->objectName().toStdString()))
|
||||
toolbar->show();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debugger_window->restoreState(m_toolbars);
|
||||
}
|
||||
|
||||
if (m_geometry.isEmpty())
|
||||
{
|
||||
// This is a newly created layout with no geometry information.
|
||||
setupDefaultLayout();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create all the dock widgets.
|
||||
KDDockWidgets::LayoutSaver saver(KDDockWidgets::RestoreOption_RelativeToMainWindow);
|
||||
if (!saver.restoreLayout(m_geometry))
|
||||
{
|
||||
// We've failed to restore the geometry, so just tear down whatever
|
||||
// dock widgets may exist and then setup the default layout.
|
||||
for (KDDockWidgets::Core::DockWidget* dock : KDDockWidgets::DockRegistry::self()->dockwidgets())
|
||||
{
|
||||
// Make sure the dock widget releases ownership of its content.
|
||||
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(dock->view());
|
||||
view->setWidget(new QWidget());
|
||||
|
||||
delete dock;
|
||||
}
|
||||
|
||||
setupDefaultLayout();
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all the dock widgets have been restored correctly.
|
||||
std::vector<QString> orphaned_debugger_widgets;
|
||||
for (auto& [unique_name, widget] : m_widgets)
|
||||
{
|
||||
auto [controller, view] = DockUtils::dockWidgetFromName(unique_name);
|
||||
if (!controller || !view)
|
||||
{
|
||||
Console.Error("Debugger: Failed to restore dock widget '%s'.", unique_name.toStdString().c_str());
|
||||
orphaned_debugger_widgets.emplace_back(unique_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete any debugger widgets that haven't been restored correctly.
|
||||
for (const QString& unique_name : orphaned_debugger_widgets)
|
||||
{
|
||||
auto widget_iterator = m_widgets.find(unique_name);
|
||||
pxAssert(widget_iterator != m_widgets.end());
|
||||
|
||||
setPrimaryDebuggerWidget(widget_iterator->second.get(), false);
|
||||
delete widget_iterator->second.get();
|
||||
m_widgets.erase(widget_iterator);
|
||||
}
|
||||
|
||||
updateDockWidgetTitles();
|
||||
}
|
||||
|
||||
bool DockLayout::canReset()
|
||||
{
|
||||
return DockTables::defaultLayout(m_base_layout) != nullptr;
|
||||
}
|
||||
|
||||
void DockLayout::reset()
|
||||
{
|
||||
pxAssert(!m_is_active);
|
||||
|
||||
for (auto& [unique_name, widget] : m_widgets)
|
||||
{
|
||||
pxAssert(widget.get());
|
||||
|
||||
delete widget;
|
||||
}
|
||||
|
||||
m_next_unique_name = 0;
|
||||
m_toolbars.clear();
|
||||
m_widgets.clear();
|
||||
m_geometry.clear();
|
||||
|
||||
const DockTables::DefaultDockLayout* base_layout = DockTables::defaultLayout(m_base_layout);
|
||||
if (!base_layout)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < base_layout->widgets.size(); i++)
|
||||
{
|
||||
auto iterator = DockTables::DEBUGGER_WIDGETS.find(base_layout->widgets[i].type);
|
||||
pxAssertRel(iterator != DockTables::DEBUGGER_WIDGETS.end(), "Invalid default layout.");
|
||||
const DockTables::DebuggerWidgetDescription& dock_description = iterator->second;
|
||||
|
||||
DebuggerWidgetParameters parameters;
|
||||
parameters.unique_name = generateNewUniqueName(base_layout->widgets[i].type.c_str());
|
||||
parameters.cpu = &DebugInterface::get(m_cpu);
|
||||
|
||||
if (parameters.unique_name.isEmpty())
|
||||
continue;
|
||||
|
||||
DebuggerWidget* widget = dock_description.create_widget(parameters);
|
||||
widget->setPrimary(true);
|
||||
m_widgets.emplace(parameters.unique_name, widget);
|
||||
}
|
||||
}
|
||||
|
||||
KDDockWidgets::Core::DockWidget* DockLayout::createDockWidget(const QString& name)
|
||||
{
|
||||
pxAssert(m_is_active);
|
||||
pxAssert(KDDockWidgets::LayoutSaver::restoreInProgress());
|
||||
|
||||
auto widget_iterator = m_widgets.find(name);
|
||||
if (widget_iterator == m_widgets.end())
|
||||
return nullptr;
|
||||
|
||||
DebuggerWidget* widget = widget_iterator->second;
|
||||
if (!widget)
|
||||
return nullptr;
|
||||
|
||||
pxAssert(widget->uniqueName() == name);
|
||||
|
||||
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(
|
||||
KDDockWidgets::Config::self().viewFactory()->createDockWidget(name));
|
||||
view->setWidget(widget);
|
||||
|
||||
return view->asController<KDDockWidgets::Core::DockWidget>();
|
||||
}
|
||||
|
||||
void DockLayout::updateDockWidgetTitles()
|
||||
{
|
||||
if (!m_is_active)
|
||||
return;
|
||||
|
||||
// Translate default debugger widget names.
|
||||
for (auto& [unique_name, widget] : m_widgets)
|
||||
widget->retranslateDisplayName();
|
||||
|
||||
// Determine if any widgets have duplicate display names.
|
||||
std::map<QString, std::vector<DebuggerWidget*>> display_name_to_widgets;
|
||||
for (auto& [unique_name, widget] : m_widgets)
|
||||
display_name_to_widgets[widget->displayNameWithoutSuffix()].emplace_back(widget.get());
|
||||
|
||||
for (auto& [display_name, widgets] : display_name_to_widgets)
|
||||
{
|
||||
std::sort(widgets.begin(), widgets.end(),
|
||||
[&](const DebuggerWidget* lhs, const DebuggerWidget* rhs) {
|
||||
return lhs->uniqueName() < rhs->uniqueName();
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < widgets.size(); i++)
|
||||
{
|
||||
std::optional<int> suffix_number;
|
||||
if (widgets.size() != 1)
|
||||
suffix_number = static_cast<int>(i + 1);
|
||||
|
||||
widgets[i]->setDisplayNameSuffixNumber(suffix_number);
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate the new names from the debugger widgets to the dock widgets.
|
||||
for (auto& [unique_name, widget] : m_widgets)
|
||||
{
|
||||
auto [controller, view] = DockUtils::dockWidgetFromName(widget->uniqueName());
|
||||
if (!controller)
|
||||
continue;
|
||||
|
||||
controller->setTitle(widget->displayName());
|
||||
}
|
||||
}
|
||||
|
||||
const std::map<QString, QPointer<DebuggerWidget>>& DockLayout::debuggerWidgets()
|
||||
{
|
||||
return m_widgets;
|
||||
}
|
||||
|
||||
bool DockLayout::hasDebuggerWidget(const QString& unique_name)
|
||||
{
|
||||
return m_widgets.find(unique_name) != m_widgets.end();
|
||||
}
|
||||
|
||||
size_t DockLayout::countDebuggerWidgetsOfType(const char* type)
|
||||
{
|
||||
size_t count = 0;
|
||||
for (const auto& [unique_name, widget] : m_widgets)
|
||||
{
|
||||
if (strcmp(widget->metaObject()->className(), type) == 0)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void DockLayout::createDebuggerWidget(const std::string& type)
|
||||
{
|
||||
pxAssert(m_is_active);
|
||||
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
auto description_iterator = DockTables::DEBUGGER_WIDGETS.find(type);
|
||||
pxAssert(description_iterator != DockTables::DEBUGGER_WIDGETS.end());
|
||||
|
||||
const DockTables::DebuggerWidgetDescription& description = description_iterator->second;
|
||||
|
||||
DebuggerWidgetParameters parameters;
|
||||
parameters.unique_name = generateNewUniqueName(type.c_str());
|
||||
parameters.cpu = &DebugInterface::get(m_cpu);
|
||||
|
||||
if (parameters.unique_name.isEmpty())
|
||||
return;
|
||||
|
||||
DebuggerWidget* widget = description.create_widget(parameters);
|
||||
m_widgets.emplace(parameters.unique_name, widget);
|
||||
|
||||
setPrimaryDebuggerWidget(widget, countDebuggerWidgetsOfType(type.c_str()) == 0);
|
||||
|
||||
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(
|
||||
KDDockWidgets::Config::self().viewFactory()->createDockWidget(widget->uniqueName()));
|
||||
view->setWidget(widget);
|
||||
|
||||
KDDockWidgets::Core::DockWidget* controller = view->asController<KDDockWidgets::Core::DockWidget>();
|
||||
pxAssert(controller);
|
||||
|
||||
DockUtils::insertDockWidgetAtPreferredLocation(controller, description.preferred_location, g_debugger_window);
|
||||
updateDockWidgetTitles();
|
||||
}
|
||||
|
||||
void DockLayout::recreateDebuggerWidget(const QString& unique_name)
|
||||
{
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
auto debugger_widget_iterator = m_widgets.find(unique_name);
|
||||
pxAssert(debugger_widget_iterator != m_widgets.end());
|
||||
|
||||
DebuggerWidget* old_debugger_widget = debugger_widget_iterator->second;
|
||||
|
||||
auto description_iterator = DockTables::DEBUGGER_WIDGETS.find(old_debugger_widget->metaObject()->className());
|
||||
pxAssert(description_iterator != DockTables::DEBUGGER_WIDGETS.end());
|
||||
|
||||
const DockTables::DebuggerWidgetDescription& description = description_iterator->second;
|
||||
|
||||
DebuggerWidgetParameters parameters;
|
||||
parameters.unique_name = old_debugger_widget->uniqueName();
|
||||
parameters.cpu = &DebugInterface::get(m_cpu);
|
||||
parameters.cpu_override = old_debugger_widget->cpuOverride();
|
||||
|
||||
DebuggerWidget* new_debugger_widget = description.create_widget(parameters);
|
||||
new_debugger_widget->setCustomDisplayName(old_debugger_widget->customDisplayName());
|
||||
new_debugger_widget->setPrimary(old_debugger_widget->isPrimary());
|
||||
debugger_widget_iterator->second = new_debugger_widget;
|
||||
|
||||
if (m_is_active)
|
||||
{
|
||||
auto [controller, view] = DockUtils::dockWidgetFromName(unique_name);
|
||||
if (view)
|
||||
view->setWidget(new_debugger_widget);
|
||||
}
|
||||
|
||||
delete old_debugger_widget;
|
||||
}
|
||||
|
||||
void DockLayout::destroyDebuggerWidget(const QString& unique_name)
|
||||
{
|
||||
pxAssert(m_is_active);
|
||||
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
auto debugger_widget_iterator = m_widgets.find(unique_name);
|
||||
if (debugger_widget_iterator == m_widgets.end())
|
||||
return;
|
||||
|
||||
setPrimaryDebuggerWidget(debugger_widget_iterator->second.get(), false);
|
||||
delete debugger_widget_iterator->second.get();
|
||||
m_widgets.erase(debugger_widget_iterator);
|
||||
|
||||
auto [controller, view] = DockUtils::dockWidgetFromName(unique_name);
|
||||
if (!controller)
|
||||
return;
|
||||
|
||||
controller->deleteLater();
|
||||
|
||||
updateDockWidgetTitles();
|
||||
}
|
||||
|
||||
void DockLayout::setPrimaryDebuggerWidget(DebuggerWidget* widget, bool is_primary)
|
||||
{
|
||||
bool present = false;
|
||||
for (auto& [unique_name, test_widget] : m_widgets)
|
||||
{
|
||||
if (test_widget.get() == widget)
|
||||
{
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!present)
|
||||
return;
|
||||
|
||||
if (is_primary)
|
||||
{
|
||||
// Set the passed widget as the primary widget.
|
||||
for (auto& [unique_name, test_widget] : m_widgets)
|
||||
{
|
||||
if (strcmp(test_widget->metaObject()->className(), widget->metaObject()->className()) == 0)
|
||||
{
|
||||
test_widget->setPrimary(test_widget.get() == widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (widget->isPrimary())
|
||||
{
|
||||
// Set an arbitrary widget as the primary widget.
|
||||
bool next = true;
|
||||
for (auto& [unique_name, test_widget] : m_widgets)
|
||||
{
|
||||
if (test_widget != widget &&
|
||||
strcmp(test_widget->metaObject()->className(), widget->metaObject()->className()) == 0)
|
||||
{
|
||||
test_widget->setPrimary(next);
|
||||
next = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't set another widget as the primary one we can't make
|
||||
// this one not the primary one.
|
||||
if (!next)
|
||||
widget->setPrimary(false);
|
||||
}
|
||||
}
|
||||
|
||||
void DockLayout::deleteFile()
|
||||
{
|
||||
if (m_layout_file_path.empty())
|
||||
return;
|
||||
|
||||
if (!FileSystem::DeleteFilePath(m_layout_file_path.c_str()))
|
||||
Console.Error("Debugger: Failed to delete layout file '%s'.", m_layout_file_path.c_str());
|
||||
}
|
||||
|
||||
bool DockLayout::save(DockLayout::Index layout_index)
|
||||
{
|
||||
if (!g_debugger_window)
|
||||
return false;
|
||||
|
||||
if (m_is_active)
|
||||
{
|
||||
m_toolbars = g_debugger_window->saveState();
|
||||
|
||||
// Store the geometry of all the dock widgets as JSON.
|
||||
KDDockWidgets::LayoutSaver saver(KDDockWidgets::RestoreOption_RelativeToMainWindow);
|
||||
m_geometry = saver.serializeLayout();
|
||||
}
|
||||
|
||||
// Serialize the layout as JSON.
|
||||
rapidjson::Document json(rapidjson::kObjectType);
|
||||
rapidjson::Document geometry;
|
||||
|
||||
const char* cpu_name = DebugInterface::cpuName(m_cpu);
|
||||
const std::string& default_layouts_hash = DockTables::hashDefaultLayouts();
|
||||
|
||||
rapidjson::Value format;
|
||||
format.SetString(DEBUGGER_LAYOUT_FILE_FORMAT, strlen(DEBUGGER_LAYOUT_FILE_FORMAT));
|
||||
json.AddMember("format", format, json.GetAllocator());
|
||||
|
||||
json.AddMember("version_major", DEBUGGER_LAYOUT_FILE_VERSION_MAJOR, json.GetAllocator());
|
||||
json.AddMember("version_minor", DEBUGGER_LAYOUT_FILE_VERSION_MINOR, json.GetAllocator());
|
||||
rapidjson::Value version_hash;
|
||||
version_hash.SetString(default_layouts_hash.c_str(), default_layouts_hash.size());
|
||||
json.AddMember("version_hash", version_hash, json.GetAllocator());
|
||||
|
||||
std::string name_str = m_name.toStdString();
|
||||
json.AddMember("name", rapidjson::Value().SetString(name_str.c_str(), name_str.size()), json.GetAllocator());
|
||||
json.AddMember("target", rapidjson::Value().SetString(cpu_name, strlen(cpu_name)), json.GetAllocator());
|
||||
json.AddMember("index", static_cast<int>(layout_index), json.GetAllocator());
|
||||
json.AddMember("isDefault", m_is_default, json.GetAllocator());
|
||||
json.AddMember("nextUniqueName", m_next_unique_name, json.GetAllocator());
|
||||
|
||||
if (!m_base_layout.empty())
|
||||
{
|
||||
rapidjson::Value base_layout;
|
||||
base_layout.SetString(m_base_layout.c_str(), m_base_layout.size());
|
||||
json.AddMember("baseLayout", base_layout, json.GetAllocator());
|
||||
}
|
||||
|
||||
if (!m_toolbars.isEmpty())
|
||||
{
|
||||
std::string toolbars_str = m_toolbars.toBase64().toStdString();
|
||||
rapidjson::Value toolbars;
|
||||
toolbars.SetString(toolbars_str.data(), toolbars_str.size(), json.GetAllocator());
|
||||
json.AddMember("toolbars", toolbars, json.GetAllocator());
|
||||
}
|
||||
|
||||
rapidjson::Value widgets(rapidjson::kArrayType);
|
||||
for (auto& [unique_name, widget] : m_widgets)
|
||||
{
|
||||
pxAssert(widget.get());
|
||||
|
||||
rapidjson::Value object(rapidjson::kObjectType);
|
||||
|
||||
std::string name_str = unique_name.toStdString();
|
||||
rapidjson::Value name;
|
||||
name.SetString(name_str.c_str(), name_str.size(), json.GetAllocator());
|
||||
object.AddMember("uniqueName", name, json.GetAllocator());
|
||||
|
||||
const char* type_str = widget->metaObject()->className();
|
||||
rapidjson::Value type;
|
||||
type.SetString(type_str, strlen(type_str), json.GetAllocator());
|
||||
object.AddMember("type", type, json.GetAllocator());
|
||||
|
||||
if (widget->cpuOverride().has_value())
|
||||
{
|
||||
const char* cpu_name = DebugInterface::cpuName(*widget->cpuOverride());
|
||||
|
||||
rapidjson::Value target;
|
||||
target.SetString(cpu_name, strlen(cpu_name));
|
||||
object.AddMember("target", target, json.GetAllocator());
|
||||
}
|
||||
|
||||
JsonValueWrapper wrapper(object, json.GetAllocator());
|
||||
widget->toJson(wrapper);
|
||||
|
||||
widgets.PushBack(object, json.GetAllocator());
|
||||
}
|
||||
json.AddMember("widgets", widgets, json.GetAllocator());
|
||||
|
||||
if (!m_geometry.isEmpty() && !geometry.Parse(m_geometry).HasParseError())
|
||||
json.AddMember("geometry", geometry, json.GetAllocator());
|
||||
|
||||
rapidjson::StringBuffer string_buffer;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(string_buffer);
|
||||
json.Accept(writer);
|
||||
|
||||
std::string safe_name = Path::SanitizeFileName(m_name.toStdString());
|
||||
|
||||
// Create a temporary file first so that we don't corrupt an existing file
|
||||
// in the case that we succeed in opening the file but fail to write our
|
||||
// data to it.
|
||||
std::string temp_file_path = Path::Combine(EmuFolders::DebuggerLayouts, safe_name + ".tmp");
|
||||
|
||||
if (!FileSystem::WriteStringToFile(temp_file_path.c_str(), string_buffer.GetString()))
|
||||
{
|
||||
Console.Error("Debugger: Failed to save temporary layout file '%s'.", temp_file_path.c_str());
|
||||
FileSystem::DeleteFilePath(temp_file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now move the layout to its final location.
|
||||
std::string file_path = Path::Combine(EmuFolders::DebuggerLayouts, safe_name + ".json");
|
||||
|
||||
if (!FileSystem::RenamePath(temp_file_path.c_str(), file_path.c_str()))
|
||||
{
|
||||
Console.Error("Debugger: Failed to move layout file to '%s'.", file_path.c_str());
|
||||
FileSystem::DeleteFilePath(temp_file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the layout has been renamed we need to delete the old file.
|
||||
if (file_path != m_layout_file_path)
|
||||
deleteFile();
|
||||
|
||||
m_layout_file_path = std::move(file_path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DockLayout::load(
|
||||
const std::string& path,
|
||||
LoadResult& result,
|
||||
DockLayout::Index& index_last_session)
|
||||
{
|
||||
pxAssert(!m_is_active);
|
||||
|
||||
result = SUCCESS;
|
||||
|
||||
std::optional<std::string> text = FileSystem::ReadFileToString(path.c_str());
|
||||
if (!text.has_value())
|
||||
{
|
||||
Console.Error("Debugger: Failed to open layout file '%s'.", path.c_str());
|
||||
result = FILE_NOT_FOUND;
|
||||
return;
|
||||
}
|
||||
|
||||
rapidjson::Document json;
|
||||
if (json.Parse(text->c_str()).HasParseError() || !json.IsObject())
|
||||
{
|
||||
Console.Error("Debugger: Failed to parse layout file '%s' as JSON.", path.c_str());
|
||||
result = INVALID_FORMAT;
|
||||
return;
|
||||
}
|
||||
|
||||
auto format = json.FindMember("format");
|
||||
if (format == json.MemberEnd() ||
|
||||
!format->value.IsString() ||
|
||||
strcmp(format->value.GetString(), DEBUGGER_LAYOUT_FILE_FORMAT) != 0)
|
||||
{
|
||||
Console.Error("Debugger: Layout file '%s' has missing or invalid 'format' property.", path.c_str());
|
||||
result = INVALID_FORMAT;
|
||||
return;
|
||||
}
|
||||
|
||||
auto version_major = json.FindMember("version_major");
|
||||
if (version_major == json.MemberEnd() || !version_major->value.IsInt())
|
||||
{
|
||||
Console.Error("Debugger: Layout file '%s' has missing or invalid 'version_major' property.", path.c_str());
|
||||
result = INVALID_FORMAT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (version_major->value.GetInt() != DEBUGGER_LAYOUT_FILE_VERSION_MAJOR)
|
||||
{
|
||||
result = MAJOR_VERSION_MISMATCH;
|
||||
return;
|
||||
}
|
||||
|
||||
auto version_minor = json.FindMember("version_minor");
|
||||
if (version_minor == json.MemberEnd() || !version_minor->value.IsInt())
|
||||
{
|
||||
Console.Error("Debugger: Layout file '%s' has missing or invalid 'version_minor' property.", path.c_str());
|
||||
result = INVALID_FORMAT;
|
||||
return;
|
||||
}
|
||||
|
||||
auto version_hash = json.FindMember("version_hash");
|
||||
if (version_hash == json.MemberEnd() || !version_hash->value.IsString())
|
||||
{
|
||||
Console.Error("Debugger: Layout file '%s' has missing or invalid 'version_hash' property.", path.c_str());
|
||||
result = INVALID_FORMAT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(version_hash->value.GetString(), DockTables::hashDefaultLayouts().c_str()) != 0)
|
||||
result = DEFAULT_LAYOUT_HASH_MISMATCH;
|
||||
|
||||
auto name = json.FindMember("name");
|
||||
if (name != json.MemberEnd() && name->value.IsString())
|
||||
m_name = name->value.GetString();
|
||||
else
|
||||
m_name = QCoreApplication::translate("DockLayout", "Unnamed");
|
||||
|
||||
m_name.truncate(DockUtils::MAX_LAYOUT_NAME_SIZE);
|
||||
|
||||
auto target = json.FindMember("target");
|
||||
m_cpu = BREAKPOINT_EE;
|
||||
if (target != json.MemberEnd() && target->value.IsString())
|
||||
{
|
||||
for (BreakPointCpu cpu : DEBUG_CPUS)
|
||||
if (strcmp(DebugInterface::cpuName(cpu), target->value.GetString()) == 0)
|
||||
m_cpu = cpu;
|
||||
}
|
||||
|
||||
auto index = json.FindMember("index");
|
||||
if (index != json.MemberEnd() && index->value.IsInt())
|
||||
index_last_session = index->value.GetInt();
|
||||
|
||||
auto is_default = json.FindMember("isDefault");
|
||||
if (is_default != json.MemberEnd() && is_default->value.IsBool())
|
||||
m_is_default = is_default->value.GetBool();
|
||||
|
||||
auto next_unique_name = json.FindMember("nextUniqueName");
|
||||
if (next_unique_name != json.MemberBegin() && next_unique_name->value.IsInt())
|
||||
m_next_unique_name = next_unique_name->value.GetInt();
|
||||
|
||||
auto base_layout = json.FindMember("baseLayout");
|
||||
if (base_layout != json.MemberEnd() && base_layout->value.IsString())
|
||||
m_base_layout = base_layout->value.GetString();
|
||||
|
||||
auto toolbars = json.FindMember("toolbars");
|
||||
if (toolbars != json.MemberEnd() && toolbars->value.IsString())
|
||||
m_toolbars = QByteArray::fromBase64(toolbars->value.GetString());
|
||||
|
||||
auto widgets = json.FindMember("widgets");
|
||||
if (widgets != json.MemberEnd() && widgets->value.IsArray())
|
||||
{
|
||||
for (rapidjson::Value& object : widgets->value.GetArray())
|
||||
{
|
||||
auto unique_name = object.FindMember("uniqueName");
|
||||
if (unique_name == object.MemberEnd() || !unique_name->value.IsString())
|
||||
continue;
|
||||
|
||||
auto widgets_iterator = m_widgets.find(unique_name->value.GetString());
|
||||
if (widgets_iterator != m_widgets.end())
|
||||
continue;
|
||||
|
||||
auto type = object.FindMember("type");
|
||||
if (type == object.MemberEnd() || !type->value.IsString())
|
||||
continue;
|
||||
|
||||
auto description = DockTables::DEBUGGER_WIDGETS.find(type->value.GetString());
|
||||
if (description == DockTables::DEBUGGER_WIDGETS.end())
|
||||
continue;
|
||||
|
||||
std::optional<BreakPointCpu> cpu_override;
|
||||
|
||||
auto target = object.FindMember("target");
|
||||
if (target != object.MemberEnd() && target->value.IsString())
|
||||
{
|
||||
for (BreakPointCpu cpu : DEBUG_CPUS)
|
||||
if (strcmp(DebugInterface::cpuName(cpu), target->value.GetString()) == 0)
|
||||
cpu_override = cpu;
|
||||
}
|
||||
|
||||
DebuggerWidgetParameters parameters;
|
||||
parameters.unique_name = unique_name->value.GetString();
|
||||
parameters.cpu = &DebugInterface::get(m_cpu);
|
||||
parameters.cpu_override = cpu_override;
|
||||
|
||||
DebuggerWidget* widget = description->second.create_widget(parameters);
|
||||
|
||||
JsonValueWrapper wrapper(object, json.GetAllocator());
|
||||
if (!widget->fromJson(wrapper))
|
||||
{
|
||||
delete widget;
|
||||
continue;
|
||||
}
|
||||
|
||||
m_widgets.emplace(unique_name->value.GetString(), widget);
|
||||
}
|
||||
}
|
||||
|
||||
auto geometry = json.FindMember("geometry");
|
||||
if (geometry != json.MemberEnd() && geometry->value.IsObject())
|
||||
{
|
||||
rapidjson::StringBuffer string_buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(string_buffer);
|
||||
geometry->value.Accept(writer);
|
||||
|
||||
m_geometry = QByteArray(string_buffer.GetString(), string_buffer.GetSize());
|
||||
}
|
||||
|
||||
m_layout_file_path = path;
|
||||
|
||||
validatePrimaryDebuggerWidgets();
|
||||
}
|
||||
|
||||
void DockLayout::validatePrimaryDebuggerWidgets()
|
||||
{
|
||||
std::map<std::string, std::vector<DebuggerWidget*>> type_to_widgets;
|
||||
for (const auto& [unique_name, widget] : m_widgets)
|
||||
type_to_widgets[widget->metaObject()->className()].emplace_back(widget.get());
|
||||
|
||||
for (auto& [type, widgets] : type_to_widgets)
|
||||
{
|
||||
u32 primary_widgets = 0;
|
||||
|
||||
// Make sure at most one widget is marked as primary.
|
||||
for (DebuggerWidget* widget : widgets)
|
||||
{
|
||||
if (widget->isPrimary())
|
||||
{
|
||||
if (primary_widgets != 0)
|
||||
widget->setPrimary(false);
|
||||
|
||||
primary_widgets++;
|
||||
}
|
||||
}
|
||||
|
||||
// If none of the widgets were marked as primary, just set the first one
|
||||
// as the primary one.
|
||||
if (primary_widgets == 0)
|
||||
widgets[0]->setPrimary(true);
|
||||
}
|
||||
}
|
||||
|
||||
void DockLayout::setupDefaultLayout()
|
||||
{
|
||||
pxAssert(m_is_active);
|
||||
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
const DockTables::DefaultDockLayout* base_layout = DockTables::defaultLayout(m_base_layout);
|
||||
if (!base_layout)
|
||||
return;
|
||||
|
||||
std::vector<KDDockWidgets::QtWidgets::DockWidget*> groups(base_layout->groups.size(), nullptr);
|
||||
|
||||
for (const DockTables::DefaultDockWidgetDescription& dock_description : base_layout->widgets)
|
||||
{
|
||||
const DockTables::DefaultDockGroupDescription& group =
|
||||
base_layout->groups[static_cast<u32>(dock_description.group)];
|
||||
|
||||
DebuggerWidget* widget = nullptr;
|
||||
for (auto& [unique_name, test_widget] : m_widgets)
|
||||
if (test_widget->metaObject()->className() == dock_description.type)
|
||||
widget = test_widget;
|
||||
|
||||
if (!widget)
|
||||
continue;
|
||||
|
||||
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(
|
||||
KDDockWidgets::Config::self().viewFactory()->createDockWidget(widget->uniqueName()));
|
||||
view->setWidget(widget);
|
||||
|
||||
if (!groups[static_cast<u32>(dock_description.group)])
|
||||
{
|
||||
KDDockWidgets::QtWidgets::DockWidget* parent = nullptr;
|
||||
if (group.parent != DockTables::DefaultDockGroup::ROOT)
|
||||
parent = groups[static_cast<u32>(group.parent)];
|
||||
|
||||
g_debugger_window->addDockWidget(view, group.location, parent);
|
||||
|
||||
groups[static_cast<u32>(dock_description.group)] = view;
|
||||
}
|
||||
else
|
||||
{
|
||||
groups[static_cast<u32>(dock_description.group)]->addDockWidgetAsTab(view);
|
||||
}
|
||||
}
|
||||
|
||||
for (KDDockWidgets::Core::Group* group : KDDockWidgets::DockRegistry::self()->groups())
|
||||
group->setCurrentTabIndex(0);
|
||||
}
|
||||
|
||||
QString DockLayout::generateNewUniqueName(const char* type)
|
||||
{
|
||||
QString name;
|
||||
do
|
||||
{
|
||||
if (m_next_unique_name == INT_MAX)
|
||||
return QString();
|
||||
|
||||
// Produce unique names that will lexicographically sort in the order
|
||||
// they were allocated. This ensures the #1, #2, etc suffixes for dock
|
||||
// widgets with conflicting names will be assigned in the correct order.
|
||||
name = QStringLiteral("%1-%2").arg(m_next_unique_name, 16, 10, QLatin1Char('0')).arg(type);
|
||||
m_next_unique_name++;
|
||||
} while (hasDebuggerWidget(name));
|
||||
return name;
|
||||
}
|
||||
163
pcsx2-qt/Debugger/Docking/DockLayout.h
Normal file
163
pcsx2-qt/Debugger/Docking/DockLayout.h
Normal file
@@ -0,0 +1,163 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Debugger/Docking/DockTables.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
#include <kddockwidgets/MainWindow.h>
|
||||
#include <kddockwidgets/DockWidget.h>
|
||||
|
||||
#include <QtCore/QPointer>
|
||||
|
||||
class DebuggerWidget;
|
||||
class DebuggerWindow;
|
||||
|
||||
extern const char* DEBUGGER_LAYOUT_FILE_FORMAT;
|
||||
|
||||
// Increment this whenever there is a breaking change to the JSON format.
|
||||
extern const u32 DEBUGGER_LAYOUT_FILE_VERSION_MAJOR;
|
||||
|
||||
// Increment this whenever there is a non-breaking change to the JSON format.
|
||||
extern const u32 DEBUGGER_LAYOUT_FILE_VERSION_MINOR;
|
||||
|
||||
class DockLayout
|
||||
{
|
||||
public:
|
||||
using Index = size_t;
|
||||
static const constexpr Index INVALID_INDEX = SIZE_MAX;
|
||||
|
||||
enum LoadResult
|
||||
{
|
||||
SUCCESS,
|
||||
FILE_NOT_FOUND,
|
||||
INVALID_FORMAT,
|
||||
MAJOR_VERSION_MISMATCH,
|
||||
DEFAULT_LAYOUT_HASH_MISMATCH,
|
||||
CONFLICTING_NAME
|
||||
};
|
||||
|
||||
// Create a layout based on a default layout.
|
||||
DockLayout(
|
||||
QString name,
|
||||
BreakPointCpu cpu,
|
||||
bool is_default,
|
||||
const std::string& base_name,
|
||||
DockLayout::Index index);
|
||||
|
||||
// Create a new blank layout.
|
||||
DockLayout(
|
||||
QString name,
|
||||
BreakPointCpu cpu,
|
||||
bool is_default,
|
||||
DockLayout::Index index);
|
||||
|
||||
// Clone an existing layout.
|
||||
DockLayout(
|
||||
QString name,
|
||||
BreakPointCpu cpu,
|
||||
bool is_default,
|
||||
const DockLayout& layout_to_clone,
|
||||
DockLayout::Index index);
|
||||
|
||||
// Load a layout from a file.
|
||||
DockLayout(
|
||||
const std::string& path,
|
||||
LoadResult& result,
|
||||
DockLayout::Index& index_last_session,
|
||||
DockLayout::Index index);
|
||||
|
||||
~DockLayout();
|
||||
|
||||
DockLayout(const DockLayout& rhs) = delete;
|
||||
DockLayout& operator=(const DockLayout& rhs) = delete;
|
||||
|
||||
DockLayout(DockLayout&& rhs) = default;
|
||||
DockLayout& operator=(DockLayout&&) = default;
|
||||
|
||||
const QString& name() const;
|
||||
void setName(QString name);
|
||||
|
||||
BreakPointCpu cpu() const;
|
||||
void setCpu(BreakPointCpu cpu);
|
||||
|
||||
bool isDefault() const;
|
||||
|
||||
// Tear down and save the state of all the dock widgets from this layout.
|
||||
void freeze();
|
||||
|
||||
// Restore the state of all the dock widgets from this layout.
|
||||
void thaw();
|
||||
|
||||
bool canReset();
|
||||
void reset();
|
||||
|
||||
KDDockWidgets::Core::DockWidget* createDockWidget(const QString& name);
|
||||
void updateDockWidgetTitles();
|
||||
|
||||
const std::map<QString, QPointer<DebuggerWidget>>& debuggerWidgets();
|
||||
bool hasDebuggerWidget(const QString& unique_name);
|
||||
size_t countDebuggerWidgetsOfType(const char* type);
|
||||
void createDebuggerWidget(const std::string& type);
|
||||
void recreateDebuggerWidget(const QString& unique_name);
|
||||
void destroyDebuggerWidget(const QString& unique_name);
|
||||
void setPrimaryDebuggerWidget(DebuggerWidget* widget, bool is_primary);
|
||||
|
||||
void deleteFile();
|
||||
|
||||
bool save(DockLayout::Index layout_index);
|
||||
|
||||
private:
|
||||
void load(
|
||||
const std::string& path,
|
||||
DockLayout::LoadResult& result,
|
||||
DockLayout::Index& index_last_session);
|
||||
|
||||
// Make sure there is only a single primary debugger widget of each type.
|
||||
void validatePrimaryDebuggerWidgets();
|
||||
|
||||
void setupDefaultLayout();
|
||||
|
||||
QString generateNewUniqueName(const char* type);
|
||||
|
||||
// The name displayed in the user interface. Also used to determine the
|
||||
// file name for the layout file.
|
||||
QString m_name;
|
||||
|
||||
// The default target for dock widgets in this layout. This can be
|
||||
// overriden on a per-widget basis.
|
||||
BreakPointCpu m_cpu;
|
||||
|
||||
// Is this one of the default layouts?
|
||||
bool m_is_default = false;
|
||||
|
||||
// A counter used to generate new unique names for dock widgets.
|
||||
int m_next_unique_name = 0;
|
||||
|
||||
// The name of the default layout which this layout was based on. This will
|
||||
// be used if the m_geometry variable above is empty.
|
||||
std::string m_base_layout;
|
||||
|
||||
// The state of all the toolbars, saved and restored using
|
||||
// QMainWindow::saveState and QMainWindow::restoreState respectively.
|
||||
QByteArray m_toolbars;
|
||||
|
||||
// All the dock widgets currently open in this layout. If this is the active
|
||||
// layout then these will be owned by the docking system, otherwise they
|
||||
// won't be and will need to be cleaned up separately.
|
||||
std::map<QString, QPointer<DebuggerWidget>> m_widgets;
|
||||
|
||||
// The geometry of all the dock widgets, converted to JSON by the
|
||||
// LayoutSaver class from KDDockWidgets.
|
||||
QByteArray m_geometry;
|
||||
|
||||
// The absolute file path of the corresponding layout file as it currently
|
||||
// exists exists on disk, or empty if no such file exists.
|
||||
std::string m_layout_file_path;
|
||||
|
||||
// If this layout is the currently selected layout this will be true,
|
||||
// otherwise it will be false.
|
||||
bool m_is_active = false;
|
||||
};
|
||||
967
pcsx2-qt/Debugger/Docking/DockManager.cpp
Normal file
967
pcsx2-qt/Debugger/Docking/DockManager.cpp
Normal file
@@ -0,0 +1,967 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "DockManager.h"
|
||||
|
||||
#include "Debugger/DebuggerWidget.h"
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
#include "Debugger/Docking/DockTables.h"
|
||||
#include "Debugger/Docking/DockViews.h"
|
||||
#include "Debugger/Docking/DropIndicators.h"
|
||||
#include "Debugger/Docking/LayoutEditorDialog.h"
|
||||
#include "Debugger/Docking/NoLayoutsWidget.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/Path.h"
|
||||
|
||||
#include <kddockwidgets/Config.h>
|
||||
#include <kddockwidgets/core/Group.h>
|
||||
#include <kddockwidgets/core/Stack.h>
|
||||
#include <kddockwidgets/core/indicators/SegmentedDropIndicatorOverlay.h>
|
||||
#include <kddockwidgets/qtwidgets/Stack.h>
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QtTranslation>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QPushButton>
|
||||
|
||||
DockManager::DockManager(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
QTimer* autosave_timer = new QTimer(this);
|
||||
connect(autosave_timer, &QTimer::timeout, this, &DockManager::saveCurrentLayout);
|
||||
autosave_timer->start(60 * 1000);
|
||||
|
||||
m_blink_timer = new QTimer(this);
|
||||
connect(m_blink_timer, &QTimer::timeout, this, &DockManager::layoutSwitcherUpdateBlink);
|
||||
}
|
||||
|
||||
void DockManager::configureDockingSystem()
|
||||
{
|
||||
std::string indicator_style = Host::GetBaseStringSettingValue(
|
||||
"Debugger/UserInterface", "DropIndicatorStyle", "Classic");
|
||||
|
||||
if (indicator_style == "Segmented" || indicator_style == "Minimalistic")
|
||||
{
|
||||
KDDockWidgets::Core::ViewFactory::s_dropIndicatorType = KDDockWidgets::DropIndicatorType::Segmented;
|
||||
DockSegmentedDropIndicatorOverlay::s_indicator_style = indicator_style;
|
||||
}
|
||||
else
|
||||
{
|
||||
KDDockWidgets::Core::ViewFactory::s_dropIndicatorType = KDDockWidgets::DropIndicatorType::Classic;
|
||||
}
|
||||
|
||||
static bool done = false;
|
||||
if (done)
|
||||
return;
|
||||
|
||||
KDDockWidgets::initFrontend(KDDockWidgets::FrontendType::QtWidgets);
|
||||
|
||||
KDDockWidgets::Config& config = KDDockWidgets::Config::self();
|
||||
|
||||
config.setFlags(
|
||||
KDDockWidgets::Config::Flag_HideTitleBarWhenTabsVisible |
|
||||
KDDockWidgets::Config::Flag_AlwaysShowTabs |
|
||||
KDDockWidgets::Config::Flag_AllowReorderTabs |
|
||||
KDDockWidgets::Config::Flag_TitleBarIsFocusable);
|
||||
|
||||
// We set this flag regardless of whether or not the windowing system
|
||||
// supports compositing since it's only used by the built-in docking
|
||||
// indicator, and we only fall back to that if compositing is disabled.
|
||||
config.setInternalFlags(KDDockWidgets::Config::InternalFlag_DisableTranslucency);
|
||||
|
||||
config.setDockWidgetFactoryFunc(&DockManager::dockWidgetFactory);
|
||||
config.setViewFactory(new DockViewFactory());
|
||||
config.setDragAboutToStartFunc(&DockManager::dragAboutToStart);
|
||||
config.setStartDragDistance(std::max(QApplication::startDragDistance(), 32));
|
||||
|
||||
done = true;
|
||||
}
|
||||
|
||||
bool DockManager::deleteLayout(DockLayout::Index layout_index)
|
||||
{
|
||||
pxAssertRel(layout_index != DockLayout::INVALID_INDEX,
|
||||
"DockManager::deleteLayout called with INVALID_INDEX.");
|
||||
|
||||
if (layout_index == m_current_layout)
|
||||
{
|
||||
DockLayout::Index other_layout = DockLayout::INVALID_INDEX;
|
||||
if (layout_index + 1 < m_layouts.size())
|
||||
other_layout = layout_index + 1;
|
||||
else if (layout_index > 0)
|
||||
other_layout = layout_index - 1;
|
||||
|
||||
switchToLayout(other_layout);
|
||||
}
|
||||
|
||||
m_layouts.at(layout_index).deleteFile();
|
||||
m_layouts.erase(m_layouts.begin() + layout_index);
|
||||
|
||||
// All the layouts after the one being deleted have been shifted over by
|
||||
// one, so adjust the current layout index accordingly.
|
||||
if (m_current_layout > layout_index && m_current_layout != DockLayout::INVALID_INDEX)
|
||||
m_current_layout--;
|
||||
|
||||
if (m_layouts.empty() && g_debugger_window)
|
||||
{
|
||||
NoLayoutsWidget* widget = new NoLayoutsWidget;
|
||||
connect(widget->createDefaultLayoutsButton(), &QPushButton::clicked, this, &DockManager::resetAllLayouts);
|
||||
|
||||
KDDockWidgets::QtWidgets::DockWidget* dock = new KDDockWidgets::QtWidgets::DockWidget("placeholder");
|
||||
dock->setTitle(tr("No Layouts"));
|
||||
dock->setWidget(widget);
|
||||
g_debugger_window->addDockWidget(dock, KDDockWidgets::Location_OnTop);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DockManager::switchToLayout(DockLayout::Index layout_index, bool blink_tab)
|
||||
{
|
||||
if (layout_index != m_current_layout)
|
||||
{
|
||||
if (m_current_layout != DockLayout::INVALID_INDEX)
|
||||
{
|
||||
DockLayout& layout = m_layouts.at(m_current_layout);
|
||||
layout.freeze();
|
||||
layout.save(m_current_layout);
|
||||
}
|
||||
|
||||
// Clear out the existing positions of toolbars so they don't affect
|
||||
// where new toolbars appear for other layouts.
|
||||
if (g_debugger_window)
|
||||
g_debugger_window->clearToolBarState();
|
||||
|
||||
updateToolBarLockState();
|
||||
|
||||
m_current_layout = layout_index;
|
||||
|
||||
if (m_current_layout != DockLayout::INVALID_INDEX)
|
||||
{
|
||||
DockLayout& layout = m_layouts.at(m_current_layout);
|
||||
layout.thaw();
|
||||
|
||||
int tab_index = static_cast<int>(layout_index);
|
||||
if (m_switcher && tab_index >= 0 && tab_index < m_plus_tab_index)
|
||||
{
|
||||
m_ignore_current_tab_changed = true;
|
||||
m_switcher->setCurrentIndex(tab_index);
|
||||
m_ignore_current_tab_changed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (blink_tab)
|
||||
layoutSwitcherStartBlink();
|
||||
}
|
||||
|
||||
bool DockManager::switchToLayoutWithCPU(BreakPointCpu cpu, bool blink_tab)
|
||||
{
|
||||
// Don't interrupt the user if the current layout already has the right CPU.
|
||||
if (m_current_layout != DockLayout::INVALID_INDEX && m_layouts.at(m_current_layout).cpu() == cpu)
|
||||
{
|
||||
switchToLayout(m_current_layout, blink_tab);
|
||||
return true;
|
||||
}
|
||||
|
||||
for (DockLayout::Index i = 0; i < m_layouts.size(); i++)
|
||||
{
|
||||
if (m_layouts[i].cpu() == cpu)
|
||||
{
|
||||
switchToLayout(i, blink_tab);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DockManager::loadLayouts()
|
||||
{
|
||||
m_layouts.clear();
|
||||
|
||||
// Load the layouts.
|
||||
FileSystem::FindResultsArray files;
|
||||
FileSystem::FindFiles(
|
||||
EmuFolders::DebuggerLayouts.c_str(),
|
||||
"*.json",
|
||||
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES,
|
||||
&files);
|
||||
|
||||
bool needs_reset = false;
|
||||
bool order_changed = false;
|
||||
std::vector<DockLayout::Index> indices_last_session;
|
||||
|
||||
for (const FILESYSTEM_FIND_DATA& ffd : files)
|
||||
{
|
||||
DockLayout::LoadResult result;
|
||||
DockLayout::Index index_last_session = DockLayout::INVALID_INDEX;
|
||||
DockLayout::Index index =
|
||||
createLayout(ffd.FileName, result, index_last_session);
|
||||
|
||||
DockLayout& layout = m_layouts.at(index);
|
||||
|
||||
// Try to make sure the layout has a unique name.
|
||||
const QString& name = layout.name();
|
||||
QString new_name = name;
|
||||
if (result == DockLayout::SUCCESS || result == DockLayout::DEFAULT_LAYOUT_HASH_MISMATCH)
|
||||
{
|
||||
for (int i = 2; hasNameConflict(new_name, index) && i < 100; i++)
|
||||
{
|
||||
if (i == 99)
|
||||
{
|
||||
result = DockLayout::CONFLICTING_NAME;
|
||||
break;
|
||||
}
|
||||
|
||||
new_name = QString("%1 #%2").arg(name).arg(i);
|
||||
}
|
||||
}
|
||||
|
||||
needs_reset |= result != DockLayout::SUCCESS;
|
||||
|
||||
if (result != DockLayout::SUCCESS && result != DockLayout::DEFAULT_LAYOUT_HASH_MISMATCH)
|
||||
{
|
||||
deleteLayout(index);
|
||||
|
||||
// Only delete the file if we've identified that it's actually a
|
||||
// layout file.
|
||||
if (result == DockLayout::MAJOR_VERSION_MISMATCH || result == DockLayout::CONFLICTING_NAME)
|
||||
FileSystem::DeleteFilePath(ffd.FileName.c_str());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (new_name != name)
|
||||
{
|
||||
layout.setName(new_name);
|
||||
layout.save(index);
|
||||
}
|
||||
|
||||
if (index_last_session != index)
|
||||
order_changed = true;
|
||||
|
||||
indices_last_session.emplace_back(index_last_session);
|
||||
}
|
||||
|
||||
// Make sure the layouts remain in the same order they were in previously.
|
||||
std::vector<DockLayout*> layout_pointers;
|
||||
for (DockLayout& layout : m_layouts)
|
||||
layout_pointers.emplace_back(&layout);
|
||||
|
||||
std::sort(layout_pointers.begin(), layout_pointers.end(),
|
||||
[this, &indices_last_session](const DockLayout* lhs, const DockLayout* rhs) {
|
||||
size_t lhs_index = lhs - m_layouts.data();
|
||||
size_t rhs_index = rhs - m_layouts.data();
|
||||
DockLayout::Index lhs_index_last_session = indices_last_session.at(lhs_index);
|
||||
DockLayout::Index rhs_index_last_session = indices_last_session.at(rhs_index);
|
||||
return lhs_index_last_session < rhs_index_last_session;
|
||||
});
|
||||
|
||||
std::vector<DockLayout> sorted_layouts;
|
||||
for (size_t i = 0; i < layout_pointers.size(); i++)
|
||||
sorted_layouts.emplace_back(std::move(*layout_pointers[i]));
|
||||
|
||||
m_layouts = std::move(sorted_layouts);
|
||||
|
||||
if (m_layouts.empty() || needs_reset)
|
||||
resetDefaultLayouts();
|
||||
else
|
||||
updateLayoutSwitcher();
|
||||
|
||||
// Make sure the indices in the existing layout files match up with the
|
||||
// indices of any new layouts.
|
||||
if (order_changed)
|
||||
saveLayouts();
|
||||
}
|
||||
|
||||
bool DockManager::saveLayouts()
|
||||
{
|
||||
for (DockLayout::Index i = 0; i < m_layouts.size(); i++)
|
||||
if (!m_layouts[i].save(i))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DockManager::saveCurrentLayout()
|
||||
{
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return true;
|
||||
|
||||
return m_layouts.at(m_current_layout).save(m_current_layout);
|
||||
}
|
||||
|
||||
void DockManager::resetAllLayouts()
|
||||
{
|
||||
switchToLayout(DockLayout::INVALID_INDEX);
|
||||
|
||||
for (DockLayout& layout : m_layouts)
|
||||
layout.deleteFile();
|
||||
|
||||
m_layouts.clear();
|
||||
|
||||
for (const DockTables::DefaultDockLayout& layout : DockTables::DEFAULT_DOCK_LAYOUTS)
|
||||
createLayout(tr(layout.name.c_str()), layout.cpu, true, layout.name);
|
||||
|
||||
switchToLayout(0);
|
||||
updateLayoutSwitcher();
|
||||
saveLayouts();
|
||||
}
|
||||
|
||||
void DockManager::resetDefaultLayouts()
|
||||
{
|
||||
switchToLayout(DockLayout::INVALID_INDEX);
|
||||
|
||||
std::vector<DockLayout> old_layouts = std::move(m_layouts);
|
||||
m_layouts = std::vector<DockLayout>();
|
||||
|
||||
for (const DockTables::DefaultDockLayout& layout : DockTables::DEFAULT_DOCK_LAYOUTS)
|
||||
createLayout(tr(layout.name.c_str()), layout.cpu, true, layout.name);
|
||||
|
||||
for (DockLayout& layout : old_layouts)
|
||||
if (!layout.isDefault())
|
||||
m_layouts.emplace_back(std::move(layout));
|
||||
else
|
||||
layout.deleteFile();
|
||||
|
||||
switchToLayout(0);
|
||||
updateLayoutSwitcher();
|
||||
saveLayouts();
|
||||
}
|
||||
|
||||
void DockManager::createToolsMenu(QMenu* menu)
|
||||
{
|
||||
menu->clear();
|
||||
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX || !g_debugger_window)
|
||||
return;
|
||||
|
||||
for (QToolBar* widget : g_debugger_window->findChildren<QToolBar*>())
|
||||
{
|
||||
QAction* action = menu->addAction(widget->windowTitle());
|
||||
action->setText(widget->windowTitle());
|
||||
action->setCheckable(true);
|
||||
action->setChecked(widget->isVisible());
|
||||
connect(action, &QAction::triggered, this, [widget]() {
|
||||
widget->setVisible(!widget->isVisible());
|
||||
});
|
||||
menu->addAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
void DockManager::createWindowsMenu(QMenu* menu)
|
||||
{
|
||||
menu->clear();
|
||||
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
DockLayout& layout = m_layouts.at(m_current_layout);
|
||||
|
||||
// Create a menu that allows for multiple dock widgets of the same type to
|
||||
// be opened.
|
||||
QMenu* add_another_menu = menu->addMenu(tr("Add Another..."));
|
||||
|
||||
std::vector<DebuggerWidget*> add_another_widgets;
|
||||
std::set<std::string> add_another_types;
|
||||
for (const auto& [unique_name, widget] : layout.debuggerWidgets())
|
||||
{
|
||||
std::string type = widget->metaObject()->className();
|
||||
|
||||
if (widget->supportsMultipleInstances() && !add_another_types.contains(type))
|
||||
{
|
||||
add_another_widgets.emplace_back(widget);
|
||||
add_another_types.emplace(type);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(add_another_widgets.begin(), add_another_widgets.end(),
|
||||
[](const DebuggerWidget* lhs, const DebuggerWidget* rhs) {
|
||||
if (lhs->displayNameWithoutSuffix() == rhs->displayNameWithoutSuffix())
|
||||
return lhs->displayNameSuffixNumber() < rhs->displayNameSuffixNumber();
|
||||
|
||||
return lhs->displayNameWithoutSuffix() < rhs->displayNameWithoutSuffix();
|
||||
});
|
||||
|
||||
for (DebuggerWidget* widget : add_another_widgets)
|
||||
{
|
||||
const char* type = widget->metaObject()->className();
|
||||
|
||||
const auto description_iterator = DockTables::DEBUGGER_WIDGETS.find(type);
|
||||
pxAssert(description_iterator != DockTables::DEBUGGER_WIDGETS.end());
|
||||
|
||||
QAction* action = add_another_menu->addAction(description_iterator->second.display_name);
|
||||
connect(action, &QAction::triggered, this, [this, type]() {
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
m_layouts.at(m_current_layout).createDebuggerWidget(type);
|
||||
});
|
||||
}
|
||||
|
||||
if (add_another_widgets.empty())
|
||||
add_another_menu->setDisabled(true);
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
struct DebuggerWidgetToggle
|
||||
{
|
||||
QString display_name;
|
||||
std::optional<int> suffix_number;
|
||||
QAction* action;
|
||||
};
|
||||
|
||||
std::vector<DebuggerWidgetToggle> toggles;
|
||||
std::set<std::string> toggle_types;
|
||||
|
||||
// Create a menu item for each open debugger widget.
|
||||
for (const auto& [unique_name, widget] : layout.debuggerWidgets())
|
||||
{
|
||||
QAction* action = new QAction(menu);
|
||||
action->setText(widget->displayName());
|
||||
action->setCheckable(true);
|
||||
action->setChecked(true);
|
||||
connect(action, &QAction::triggered, this, [this, unique_name]() {
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
m_layouts.at(m_current_layout).destroyDebuggerWidget(unique_name);
|
||||
});
|
||||
|
||||
DebuggerWidgetToggle& toggle = toggles.emplace_back();
|
||||
toggle.display_name = widget->displayNameWithoutSuffix();
|
||||
toggle.suffix_number = widget->displayNameSuffixNumber();
|
||||
toggle.action = action;
|
||||
|
||||
toggle_types.emplace(widget->metaObject()->className());
|
||||
}
|
||||
|
||||
// Create menu items to open debugger widgets without any open instances.
|
||||
for (const auto& [type, desc] : DockTables::DEBUGGER_WIDGETS)
|
||||
{
|
||||
if (!toggle_types.contains(type))
|
||||
{
|
||||
QString display_name = QCoreApplication::translate("DebuggerWidget", desc.display_name);
|
||||
|
||||
QAction* action = new QAction(menu);
|
||||
action->setText(display_name);
|
||||
action->setCheckable(true);
|
||||
action->setChecked(false);
|
||||
connect(action, &QAction::triggered, this, [this, type]() {
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
m_layouts.at(m_current_layout).createDebuggerWidget(type);
|
||||
});
|
||||
|
||||
DebuggerWidgetToggle& toggle = toggles.emplace_back();
|
||||
toggle.display_name = display_name;
|
||||
toggle.suffix_number = std::nullopt;
|
||||
toggle.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(toggles.begin(), toggles.end(),
|
||||
[](const DebuggerWidgetToggle& lhs, const DebuggerWidgetToggle& rhs) {
|
||||
if (lhs.display_name == rhs.display_name)
|
||||
return lhs.suffix_number < rhs.suffix_number;
|
||||
|
||||
return lhs.display_name < rhs.display_name;
|
||||
});
|
||||
|
||||
for (const DebuggerWidgetToggle& toggle : toggles)
|
||||
menu->addAction(toggle.action);
|
||||
}
|
||||
|
||||
QWidget* DockManager::createLayoutSwitcher(QWidget* menu_bar)
|
||||
{
|
||||
QWidget* container = new QWidget;
|
||||
|
||||
QHBoxLayout* layout = new QHBoxLayout;
|
||||
layout->setContentsMargins(0, 2, 2, 0);
|
||||
container->setLayout(layout);
|
||||
|
||||
QWidget* menu_wrapper = new QWidget;
|
||||
menu_wrapper->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
layout->addWidget(menu_wrapper);
|
||||
|
||||
QHBoxLayout* menu_layout = new QHBoxLayout;
|
||||
menu_layout->setContentsMargins(0, 4, 0, 4);
|
||||
menu_wrapper->setLayout(menu_layout);
|
||||
|
||||
menu_layout->addWidget(menu_bar);
|
||||
|
||||
m_switcher = new QTabBar;
|
||||
m_switcher->setContentsMargins(0, 0, 0, 0);
|
||||
m_switcher->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
m_switcher->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
m_switcher->setMovable(true);
|
||||
layout->addWidget(m_switcher);
|
||||
|
||||
updateLayoutSwitcher();
|
||||
|
||||
connect(m_switcher, &QTabBar::tabMoved, this, &DockManager::layoutSwitcherTabMoved);
|
||||
connect(m_switcher, &QTabBar::customContextMenuRequested, this, &DockManager::layoutSwitcherContextMenu);
|
||||
|
||||
QWidget* spacer = new QWidget;
|
||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
layout->addWidget(spacer);
|
||||
|
||||
bool layout_locked = Host::GetBaseBoolSettingValue("Debugger/UserInterface", "LayoutLocked", true);
|
||||
|
||||
QPushButton* lock_layout_toggle = new QPushButton;
|
||||
lock_layout_toggle->setCheckable(true);
|
||||
lock_layout_toggle->setChecked(layout_locked);
|
||||
lock_layout_toggle->setFlat(true);
|
||||
connect(lock_layout_toggle, &QPushButton::toggled, this, [this, lock_layout_toggle](bool checked) {
|
||||
setLayoutLocked(checked, lock_layout_toggle, true);
|
||||
});
|
||||
layout->addWidget(lock_layout_toggle);
|
||||
|
||||
setLayoutLocked(layout_locked, lock_layout_toggle, false);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
void DockManager::updateLayoutSwitcher()
|
||||
{
|
||||
if (!m_switcher)
|
||||
return;
|
||||
|
||||
disconnect(m_tab_connection);
|
||||
|
||||
for (int i = m_switcher->count(); i > 0; i--)
|
||||
m_switcher->removeTab(i - 1);
|
||||
|
||||
for (DockLayout& layout : m_layouts)
|
||||
{
|
||||
const char* cpu_name = DebugInterface::cpuName(layout.cpu());
|
||||
QString tab_name = QString("%1 (%2)").arg(layout.name()).arg(cpu_name);
|
||||
m_switcher->addTab(tab_name);
|
||||
}
|
||||
|
||||
m_plus_tab_index = m_switcher->addTab("+");
|
||||
m_current_tab_index = m_current_layout;
|
||||
|
||||
if (m_current_layout != DockLayout::INVALID_INDEX)
|
||||
m_switcher->setCurrentIndex(m_current_layout);
|
||||
|
||||
// If we don't have any layouts, the currently selected tab will never be
|
||||
// changed, so we respond to all clicks instead.
|
||||
if (!m_layouts.empty())
|
||||
m_tab_connection = connect(m_switcher, &QTabBar::currentChanged, this, &DockManager::layoutSwitcherTabChanged);
|
||||
else
|
||||
m_tab_connection = connect(m_switcher, &QTabBar::tabBarClicked, this, &DockManager::layoutSwitcherTabChanged);
|
||||
|
||||
layoutSwitcherStopBlink();
|
||||
}
|
||||
|
||||
void DockManager::layoutSwitcherTabChanged(int index)
|
||||
{
|
||||
// Prevent recursion.
|
||||
if (m_ignore_current_tab_changed)
|
||||
return;
|
||||
|
||||
if (index == m_plus_tab_index)
|
||||
{
|
||||
if (m_current_tab_index >= 0 && m_current_tab_index < m_plus_tab_index)
|
||||
{
|
||||
m_ignore_current_tab_changed = true;
|
||||
m_switcher->setCurrentIndex(m_current_tab_index);
|
||||
m_ignore_current_tab_changed = false;
|
||||
}
|
||||
|
||||
auto name_validator = [this](const QString& name) {
|
||||
return !hasNameConflict(name, DockLayout::INVALID_INDEX);
|
||||
};
|
||||
|
||||
bool can_clone_current_layout = m_current_layout != DockLayout::INVALID_INDEX;
|
||||
|
||||
QPointer<LayoutEditorDialog> dialog = new LayoutEditorDialog(
|
||||
name_validator, can_clone_current_layout, g_debugger_window);
|
||||
|
||||
if (dialog->exec() == QDialog::Accepted && name_validator(dialog->name()))
|
||||
{
|
||||
DockLayout::Index new_layout = DockLayout::INVALID_INDEX;
|
||||
|
||||
const auto [mode, index] = dialog->initialState();
|
||||
switch (mode)
|
||||
{
|
||||
case LayoutEditorDialog::DEFAULT_LAYOUT:
|
||||
{
|
||||
const DockTables::DefaultDockLayout& default_layout = DockTables::DEFAULT_DOCK_LAYOUTS.at(index);
|
||||
new_layout = createLayout(dialog->name(), dialog->cpu(), false, default_layout.name);
|
||||
break;
|
||||
}
|
||||
case LayoutEditorDialog::BLANK_LAYOUT:
|
||||
{
|
||||
new_layout = createLayout(dialog->name(), dialog->cpu(), false);
|
||||
break;
|
||||
}
|
||||
case LayoutEditorDialog::CLONE_LAYOUT:
|
||||
{
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
DockLayout::Index old_layout = m_current_layout;
|
||||
|
||||
// Freeze the current layout so we can copy the geometry.
|
||||
switchToLayout(DockLayout::INVALID_INDEX);
|
||||
|
||||
new_layout = createLayout(dialog->name(), dialog->cpu(), false, m_layouts.at(old_layout));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updateLayoutSwitcher();
|
||||
switchToLayout(new_layout);
|
||||
}
|
||||
|
||||
delete dialog.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
DockLayout::Index layout_index = static_cast<DockLayout::Index>(index);
|
||||
if (layout_index < 0 || layout_index >= m_layouts.size())
|
||||
return;
|
||||
|
||||
switchToLayout(layout_index);
|
||||
m_current_tab_index = index;
|
||||
}
|
||||
}
|
||||
|
||||
void DockManager::layoutSwitcherTabMoved(int from, int to)
|
||||
{
|
||||
DockLayout::Index from_index = static_cast<DockLayout::Index>(from);
|
||||
DockLayout::Index to_index = static_cast<DockLayout::Index>(to);
|
||||
|
||||
if (from_index >= m_layouts.size() || to_index >= m_layouts.size())
|
||||
{
|
||||
// This happens when the user tries to move a layout to the right of the
|
||||
// plus button.
|
||||
updateLayoutSwitcher();
|
||||
return;
|
||||
}
|
||||
|
||||
DockLayout& from_layout = m_layouts[from_index];
|
||||
DockLayout& to_layout = m_layouts[to_index];
|
||||
|
||||
std::swap(from_layout, to_layout);
|
||||
|
||||
from_layout.save(from_index);
|
||||
to_layout.save(to_index);
|
||||
|
||||
if (from_index == m_current_layout)
|
||||
m_current_layout = to_index;
|
||||
else if (to_index == m_current_layout)
|
||||
m_current_layout = from_index;
|
||||
}
|
||||
|
||||
void DockManager::layoutSwitcherContextMenu(QPoint pos)
|
||||
{
|
||||
DockLayout::Index layout_index = static_cast<DockLayout::Index>(m_switcher->tabAt(pos));
|
||||
if (layout_index >= m_layouts.size())
|
||||
return;
|
||||
|
||||
DockLayout& layout = m_layouts[layout_index];
|
||||
|
||||
QMenu* menu = new QMenu(m_switcher);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QAction* edit_action = menu->addAction(tr("Edit Layout"));
|
||||
connect(edit_action, &QAction::triggered, [this, layout_index]() {
|
||||
if (layout_index >= m_layouts.size())
|
||||
return;
|
||||
|
||||
DockLayout& layout = m_layouts[layout_index];
|
||||
|
||||
auto name_validator = [this, layout_index](const QString& name) {
|
||||
return !hasNameConflict(name, layout_index);
|
||||
};
|
||||
|
||||
QPointer<LayoutEditorDialog> dialog = new LayoutEditorDialog(
|
||||
layout.name(), layout.cpu(), name_validator, g_debugger_window);
|
||||
|
||||
if (dialog->exec() != QDialog::Accepted || !name_validator(dialog->name()))
|
||||
return;
|
||||
|
||||
layout.setName(dialog->name());
|
||||
layout.setCpu(dialog->cpu());
|
||||
|
||||
layout.save(layout_index);
|
||||
|
||||
delete dialog.get();
|
||||
|
||||
updateLayoutSwitcher();
|
||||
});
|
||||
|
||||
QAction* reset_action = menu->addAction(tr("Reset Layout"));
|
||||
reset_action->setEnabled(layout.canReset());
|
||||
reset_action->connect(reset_action, &QAction::triggered, [this, layout_index]() {
|
||||
if (layout_index >= m_layouts.size())
|
||||
return;
|
||||
|
||||
DockLayout& layout = m_layouts[layout_index];
|
||||
if (!layout.canReset())
|
||||
return;
|
||||
|
||||
QString text = tr("Are you sure you want to reset layout '%1'?").arg(layout.name());
|
||||
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
bool current_layout = layout_index == m_current_layout;
|
||||
|
||||
if (current_layout)
|
||||
switchToLayout(DockLayout::INVALID_INDEX);
|
||||
|
||||
layout.reset();
|
||||
layout.save(layout_index);
|
||||
|
||||
if (current_layout)
|
||||
switchToLayout(layout_index);
|
||||
});
|
||||
|
||||
QAction* delete_action = menu->addAction(tr("Delete Layout"));
|
||||
connect(delete_action, &QAction::triggered, [this, layout_index]() {
|
||||
if (layout_index >= m_layouts.size())
|
||||
return;
|
||||
|
||||
DockLayout& layout = m_layouts[layout_index];
|
||||
|
||||
QString text = tr("Are you sure you want to delete layout '%1'?").arg(layout.name());
|
||||
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
deleteLayout(layout_index);
|
||||
updateLayoutSwitcher();
|
||||
});
|
||||
|
||||
menu->popup(m_switcher->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void DockManager::layoutSwitcherStartBlink()
|
||||
{
|
||||
if (!m_switcher)
|
||||
return;
|
||||
|
||||
layoutSwitcherStopBlink();
|
||||
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
m_blink_tab = m_current_layout;
|
||||
m_blink_stage = 0;
|
||||
m_blink_timer->start(500);
|
||||
|
||||
layoutSwitcherUpdateBlink();
|
||||
}
|
||||
|
||||
void DockManager::layoutSwitcherUpdateBlink()
|
||||
{
|
||||
if (!m_switcher)
|
||||
return;
|
||||
|
||||
if (m_blink_tab < m_switcher->count())
|
||||
{
|
||||
if (m_blink_stage % 2 == 0)
|
||||
m_switcher->setTabTextColor(m_blink_tab, Qt::red);
|
||||
else
|
||||
m_switcher->setTabTextColor(m_blink_tab, m_switcher->palette().text().color());
|
||||
}
|
||||
|
||||
m_blink_stage++;
|
||||
|
||||
if (m_blink_stage > 7)
|
||||
m_blink_timer->stop();
|
||||
}
|
||||
|
||||
void DockManager::layoutSwitcherStopBlink()
|
||||
{
|
||||
if (m_blink_timer->isActive())
|
||||
{
|
||||
if (m_blink_tab < m_switcher->count())
|
||||
m_switcher->setTabTextColor(m_blink_tab, m_switcher->palette().text().color());
|
||||
|
||||
m_blink_timer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
bool DockManager::hasNameConflict(const QString& name, DockLayout::Index layout_index)
|
||||
{
|
||||
std::string safe_name = Path::SanitizeFileName(name.toStdString());
|
||||
for (DockLayout::Index i = 0; i < m_layouts.size(); i++)
|
||||
{
|
||||
std::string other_safe_name = Path::SanitizeFileName(m_layouts[i].name().toStdString());
|
||||
if (i != layout_index && StringUtil::compareNoCase(other_safe_name, safe_name))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DockManager::updateDockWidgetTitles()
|
||||
{
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
m_layouts.at(m_current_layout).updateDockWidgetTitles();
|
||||
}
|
||||
|
||||
const std::map<QString, QPointer<DebuggerWidget>>& DockManager::debuggerWidgets()
|
||||
{
|
||||
static std::map<QString, QPointer<DebuggerWidget>> dummy;
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return dummy;
|
||||
|
||||
return m_layouts.at(m_current_layout).debuggerWidgets();
|
||||
}
|
||||
|
||||
size_t DockManager::countDebuggerWidgetsOfType(const char* type)
|
||||
{
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return 0;
|
||||
|
||||
return m_layouts.at(m_current_layout).countDebuggerWidgetsOfType(type);
|
||||
}
|
||||
|
||||
void DockManager::recreateDebuggerWidget(const QString& unique_name)
|
||||
{
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
m_layouts.at(m_current_layout).recreateDebuggerWidget(unique_name);
|
||||
}
|
||||
|
||||
void DockManager::destroyDebuggerWidget(const QString& unique_name)
|
||||
{
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
m_layouts.at(m_current_layout).destroyDebuggerWidget(unique_name);
|
||||
}
|
||||
|
||||
void DockManager::setPrimaryDebuggerWidget(DebuggerWidget* widget, bool is_primary)
|
||||
{
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
m_layouts.at(m_current_layout).setPrimaryDebuggerWidget(widget, is_primary);
|
||||
}
|
||||
|
||||
void DockManager::switchToDebuggerWidget(DebuggerWidget* widget)
|
||||
{
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
for (const auto& [unique_name, test_widget] : m_layouts.at(m_current_layout).debuggerWidgets())
|
||||
{
|
||||
if (widget == test_widget)
|
||||
{
|
||||
auto [controller, view] = DockUtils::dockWidgetFromName(unique_name);
|
||||
controller->setAsCurrentTab();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DockManager::updateStyleSheets()
|
||||
{
|
||||
for (DockLayout& layout : m_layouts)
|
||||
for (const auto& [unique_name, widget] : layout.debuggerWidgets())
|
||||
widget->updateStyleSheet();
|
||||
}
|
||||
|
||||
bool DockManager::isLayoutLocked()
|
||||
{
|
||||
return m_layout_locked;
|
||||
}
|
||||
|
||||
void DockManager::setLayoutLocked(bool locked, QPushButton* lock_layout_toggle, bool write_back)
|
||||
{
|
||||
m_layout_locked = locked;
|
||||
|
||||
if (lock_layout_toggle)
|
||||
{
|
||||
if (m_layout_locked)
|
||||
{
|
||||
lock_layout_toggle->setText(tr("Layout Locked"));
|
||||
lock_layout_toggle->setIcon(QIcon::fromTheme(QString::fromUtf8("padlock-lock")));
|
||||
}
|
||||
else
|
||||
{
|
||||
lock_layout_toggle->setText(tr("Layout Unlocked"));
|
||||
lock_layout_toggle->setIcon(QIcon::fromTheme(QString::fromUtf8("padlock-unlock")));
|
||||
}
|
||||
}
|
||||
|
||||
updateToolBarLockState();
|
||||
|
||||
for (KDDockWidgets::Core::Group* group : KDDockWidgets::DockRegistry::self()->groups())
|
||||
{
|
||||
auto stack = static_cast<KDDockWidgets::QtWidgets::Stack*>(group->stack()->view());
|
||||
stack->setTabsClosable(!m_layout_locked);
|
||||
|
||||
// HACK: Make sure the sizes of the tabs get updated.
|
||||
if (stack->tabBar()->count() > 0)
|
||||
stack->tabBar()->setTabText(0, stack->tabBar()->tabText(0));
|
||||
}
|
||||
|
||||
if (write_back)
|
||||
{
|
||||
Host::SetBaseBoolSettingValue("Debugger/UserInterface", "LayoutLocked", m_layout_locked);
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
}
|
||||
|
||||
void DockManager::updateToolBarLockState()
|
||||
{
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
for (QToolBar* toolbar : g_debugger_window->findChildren<QToolBar*>())
|
||||
toolbar->setMovable(!m_layout_locked || toolbar->isFloating());
|
||||
}
|
||||
|
||||
std::optional<BreakPointCpu> DockManager::cpu()
|
||||
{
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return std::nullopt;
|
||||
|
||||
return m_layouts.at(m_current_layout).cpu();
|
||||
}
|
||||
|
||||
KDDockWidgets::Core::DockWidget* DockManager::dockWidgetFactory(const QString& name)
|
||||
{
|
||||
if (!g_debugger_window)
|
||||
return nullptr;
|
||||
|
||||
DockManager& manager = g_debugger_window->dockManager();
|
||||
if (manager.m_current_layout == DockLayout::INVALID_INDEX)
|
||||
return nullptr;
|
||||
|
||||
return manager.m_layouts.at(manager.m_current_layout).createDockWidget(name);
|
||||
}
|
||||
|
||||
bool DockManager::dragAboutToStart(KDDockWidgets::Core::Draggable* draggable)
|
||||
{
|
||||
bool locked = true;
|
||||
if (g_debugger_window)
|
||||
locked = g_debugger_window->dockManager().isLayoutLocked();
|
||||
|
||||
KDDockWidgets::Config::self().setDropIndicatorsInhibited(locked);
|
||||
|
||||
if (draggable->isInProgrammaticDrag())
|
||||
return true;
|
||||
|
||||
// Allow floating windows to be dragged around even if the layout is locked.
|
||||
if (draggable->isWindow())
|
||||
return true;
|
||||
|
||||
if (!g_debugger_window)
|
||||
return false;
|
||||
|
||||
return !locked;
|
||||
}
|
||||
118
pcsx2-qt/Debugger/Docking/DockManager.h
Normal file
118
pcsx2-qt/Debugger/Docking/DockManager.h
Normal file
@@ -0,0 +1,118 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Debugger/Docking/DockLayout.h"
|
||||
|
||||
#include <kddockwidgets/MainWindow.h>
|
||||
#include <kddockwidgets/DockWidget.h>
|
||||
#include <kddockwidgets/core/DockRegistry.h>
|
||||
#include <kddockwidgets/core/DockWidget.h>
|
||||
#include <kddockwidgets/core/Draggable_p.h>
|
||||
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QTabBar>
|
||||
|
||||
class DockManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DockManager(QObject* parent = nullptr);
|
||||
|
||||
DockManager(const DockManager& rhs) = delete;
|
||||
DockManager& operator=(const DockManager& rhs) = delete;
|
||||
|
||||
DockManager(DockManager&& rhs) = delete;
|
||||
DockManager& operator=(DockManager&&) = delete;
|
||||
|
||||
// This needs to be called before any KDDockWidgets objects are created
|
||||
// including the debugger window itself.
|
||||
static void configureDockingSystem();
|
||||
|
||||
template <typename... Args>
|
||||
DockLayout::Index createLayout(Args&&... args)
|
||||
{
|
||||
DockLayout::Index layout_index = m_layouts.size();
|
||||
|
||||
if (m_layouts.empty())
|
||||
{
|
||||
// Delete the placeholder created in DockManager::deleteLayout.
|
||||
for (KDDockWidgets::Core::DockWidget* dock : KDDockWidgets::DockRegistry::self()->dockwidgets())
|
||||
delete dock;
|
||||
}
|
||||
|
||||
m_layouts.emplace_back(std::forward<Args>(args)..., layout_index);
|
||||
|
||||
return layout_index;
|
||||
}
|
||||
|
||||
bool deleteLayout(DockLayout::Index layout_index);
|
||||
|
||||
void switchToLayout(DockLayout::Index layout_index, bool blink_tab = false);
|
||||
bool switchToLayoutWithCPU(BreakPointCpu cpu, bool blink_tab = false);
|
||||
|
||||
void loadLayouts();
|
||||
bool saveLayouts();
|
||||
bool saveCurrentLayout();
|
||||
|
||||
QString currentLayoutName();
|
||||
bool canResetCurrentLayout();
|
||||
|
||||
void resetCurrentLayout();
|
||||
void resetDefaultLayouts();
|
||||
void resetAllLayouts();
|
||||
|
||||
void createToolsMenu(QMenu* menu);
|
||||
void createWindowsMenu(QMenu* menu);
|
||||
|
||||
QWidget* createLayoutSwitcher(QWidget* menu_bar);
|
||||
void updateLayoutSwitcher();
|
||||
void layoutSwitcherTabChanged(int index);
|
||||
void layoutSwitcherTabMoved(int from, int to);
|
||||
void layoutSwitcherContextMenu(QPoint pos);
|
||||
void layoutSwitcherStartBlink();
|
||||
void layoutSwitcherUpdateBlink();
|
||||
void layoutSwitcherStopBlink();
|
||||
|
||||
bool hasNameConflict(const QString& name, DockLayout::Index layout_index);
|
||||
|
||||
void updateDockWidgetTitles();
|
||||
|
||||
const std::map<QString, QPointer<DebuggerWidget>>& debuggerWidgets();
|
||||
size_t countDebuggerWidgetsOfType(const char* type);
|
||||
void recreateDebuggerWidget(const QString& unique_name);
|
||||
void destroyDebuggerWidget(const QString& unique_name);
|
||||
void setPrimaryDebuggerWidget(DebuggerWidget* widget, bool is_primary);
|
||||
void switchToDebuggerWidget(DebuggerWidget* widget);
|
||||
|
||||
void updateStyleSheets();
|
||||
|
||||
bool isLayoutLocked();
|
||||
void setLayoutLocked(bool locked, QPushButton* lock_layout_toggle, bool write_back);
|
||||
void updateToolBarLockState();
|
||||
|
||||
std::optional<BreakPointCpu> cpu();
|
||||
|
||||
private:
|
||||
static KDDockWidgets::Core::DockWidget* dockWidgetFactory(const QString& name);
|
||||
static bool dragAboutToStart(KDDockWidgets::Core::Draggable* draggable);
|
||||
|
||||
std::vector<DockLayout> m_layouts;
|
||||
DockLayout::Index m_current_layout = DockLayout::INVALID_INDEX;
|
||||
|
||||
QTabBar* m_switcher = nullptr;
|
||||
int m_plus_tab_index = -1;
|
||||
int m_current_tab_index = -1;
|
||||
bool m_ignore_current_tab_changed = false;
|
||||
|
||||
QMetaObject::Connection m_tab_connection;
|
||||
|
||||
bool m_layout_locked = true;
|
||||
|
||||
QTimer* m_blink_timer = nullptr;
|
||||
int m_blink_tab = 0;
|
||||
int m_blink_stage = 0;
|
||||
};
|
||||
226
pcsx2-qt/Debugger/Docking/DockTables.cpp
Normal file
226
pcsx2-qt/Debugger/Docking/DockTables.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "DockTables.h"
|
||||
|
||||
#include "Debugger/DebuggerEvents.h"
|
||||
#include "Debugger/DisassemblyWidget.h"
|
||||
#include "Debugger/RegisterWidget.h"
|
||||
#include "Debugger/StackWidget.h"
|
||||
#include "Debugger/ThreadWidget.h"
|
||||
#include "Debugger/Breakpoints/BreakpointWidget.h"
|
||||
#include "Debugger/Memory/MemorySearchWidget.h"
|
||||
#include "Debugger/Memory/MemoryViewWidget.h"
|
||||
#include "Debugger/Memory/SavedAddressesWidget.h"
|
||||
#include "Debugger/SymbolTree/SymbolTreeWidgets.h"
|
||||
|
||||
#include "common/MD5Digest.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
using namespace DockUtils;
|
||||
|
||||
#define DEBUGGER_WIDGET(type, display_name, preferred_location) \
|
||||
{ \
|
||||
#type, \
|
||||
{ \
|
||||
[](const DebuggerWidgetParameters& parameters) -> DebuggerWidget* { \
|
||||
DebuggerWidget* widget = new type(parameters); \
|
||||
widget->handleEvent(DebuggerEvents::Refresh()); \
|
||||
return widget; \
|
||||
}, \
|
||||
display_name, \
|
||||
preferred_location \
|
||||
} \
|
||||
}
|
||||
|
||||
const std::map<std::string, DockTables::DebuggerWidgetDescription> DockTables::DEBUGGER_WIDGETS = {
|
||||
DEBUGGER_WIDGET(BreakpointWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Breakpoints"), BOTTOM_MIDDLE),
|
||||
DEBUGGER_WIDGET(DisassemblyWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Disassembly"), TOP_RIGHT),
|
||||
DEBUGGER_WIDGET(FunctionTreeWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Functions"), TOP_LEFT),
|
||||
DEBUGGER_WIDGET(GlobalVariableTreeWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Globals"), BOTTOM_MIDDLE),
|
||||
DEBUGGER_WIDGET(LocalVariableTreeWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Locals"), BOTTOM_MIDDLE),
|
||||
DEBUGGER_WIDGET(MemorySearchWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Memory Search"), TOP_LEFT),
|
||||
DEBUGGER_WIDGET(MemoryViewWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Memory"), BOTTOM_MIDDLE),
|
||||
DEBUGGER_WIDGET(ParameterVariableTreeWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Parameters"), BOTTOM_MIDDLE),
|
||||
DEBUGGER_WIDGET(RegisterWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Registers"), TOP_LEFT),
|
||||
DEBUGGER_WIDGET(SavedAddressesWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Saved Addresses"), BOTTOM_MIDDLE),
|
||||
DEBUGGER_WIDGET(StackWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Stack"), BOTTOM_MIDDLE),
|
||||
DEBUGGER_WIDGET(ThreadWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Threads"), BOTTOM_MIDDLE),
|
||||
};
|
||||
|
||||
#undef DEBUGGER_WIDGET
|
||||
|
||||
const std::vector<DockTables::DefaultDockLayout> DockTables::DEFAULT_DOCK_LAYOUTS = {
|
||||
{
|
||||
.name = QT_TRANSLATE_NOOP("DebuggerLayout", "R5900"),
|
||||
.cpu = BREAKPOINT_EE,
|
||||
.groups = {
|
||||
/* [DefaultDockGroup::TOP_RIGHT] = */ {KDDockWidgets::Location_OnRight, DefaultDockGroup::ROOT},
|
||||
/* [DefaultDockGroup::BOTTOM] = */ {KDDockWidgets::Location_OnBottom, DefaultDockGroup::TOP_RIGHT},
|
||||
/* [DefaultDockGroup::TOP_LEFT] = */ {KDDockWidgets::Location_OnLeft, DefaultDockGroup::TOP_RIGHT},
|
||||
},
|
||||
.widgets = {
|
||||
/* DefaultDockGroup::TOP_RIGHT */
|
||||
{"DisassemblyWidget", DefaultDockGroup::TOP_RIGHT},
|
||||
/* DefaultDockGroup::BOTTOM */
|
||||
{"MemoryViewWidget", DefaultDockGroup::BOTTOM},
|
||||
{"BreakpointWidget", DefaultDockGroup::BOTTOM},
|
||||
{"ThreadWidget", DefaultDockGroup::BOTTOM},
|
||||
{"StackWidget", DefaultDockGroup::BOTTOM},
|
||||
{"SavedAddressesWidget", DefaultDockGroup::BOTTOM},
|
||||
{"GlobalVariableTreeWidget", DefaultDockGroup::BOTTOM},
|
||||
{"LocalVariableTreeWidget", DefaultDockGroup::BOTTOM},
|
||||
{"ParameterVariableTreeWidget", DefaultDockGroup::BOTTOM},
|
||||
/* DefaultDockGroup::TOP_LEFT */
|
||||
{"RegisterWidget", DefaultDockGroup::TOP_LEFT},
|
||||
{"FunctionTreeWidget", DefaultDockGroup::TOP_LEFT},
|
||||
{"MemorySearchWidget", DefaultDockGroup::TOP_LEFT},
|
||||
},
|
||||
.toolbars = {
|
||||
"toolBarDebug",
|
||||
"toolBarFile",
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = QT_TRANSLATE_NOOP("DebuggerLayout", "R3000"),
|
||||
.cpu = BREAKPOINT_IOP,
|
||||
.groups = {
|
||||
/* [DefaultDockGroup::TOP_RIGHT] = */ {KDDockWidgets::Location_OnRight, DefaultDockGroup::ROOT},
|
||||
/* [DefaultDockGroup::BOTTOM] = */ {KDDockWidgets::Location_OnBottom, DefaultDockGroup::TOP_RIGHT},
|
||||
/* [DefaultDockGroup::TOP_LEFT] = */ {KDDockWidgets::Location_OnLeft, DefaultDockGroup::TOP_RIGHT},
|
||||
},
|
||||
.widgets = {
|
||||
/* DefaultDockGroup::TOP_RIGHT */
|
||||
{"DisassemblyWidget", DefaultDockGroup::TOP_RIGHT},
|
||||
/* DefaultDockGroup::BOTTOM */
|
||||
{"MemoryViewWidget", DefaultDockGroup::BOTTOM},
|
||||
{"BreakpointWidget", DefaultDockGroup::BOTTOM},
|
||||
{"ThreadWidget", DefaultDockGroup::BOTTOM},
|
||||
{"StackWidget", DefaultDockGroup::BOTTOM},
|
||||
{"SavedAddressesWidget", DefaultDockGroup::BOTTOM},
|
||||
{"GlobalVariableTreeWidget", DefaultDockGroup::BOTTOM},
|
||||
{"LocalVariableTreeWidget", DefaultDockGroup::BOTTOM},
|
||||
{"ParameterVariableTreeWidget", DefaultDockGroup::BOTTOM},
|
||||
/* DefaultDockGroup::TOP_LEFT */
|
||||
{"RegisterWidget", DefaultDockGroup::TOP_LEFT},
|
||||
{"FunctionTreeWidget", DefaultDockGroup::TOP_LEFT},
|
||||
{"MemorySearchWidget", DefaultDockGroup::TOP_LEFT},
|
||||
},
|
||||
.toolbars = {
|
||||
"toolBarDebug",
|
||||
"toolBarFile",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const DockTables::DefaultDockLayout* DockTables::defaultLayout(const std::string& name)
|
||||
{
|
||||
for (const DockTables::DefaultDockLayout& default_layout : DockTables::DEFAULT_DOCK_LAYOUTS)
|
||||
if (default_layout.name == name)
|
||||
return &default_layout;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string& DockTables::hashDefaultLayouts()
|
||||
{
|
||||
static std::string hash;
|
||||
if (!hash.empty())
|
||||
return hash;
|
||||
|
||||
MD5Digest md5;
|
||||
|
||||
u32 hash_version = 1;
|
||||
md5.Update(&hash_version, sizeof(hash_version));
|
||||
|
||||
u32 layout_count = static_cast<u32>(DEFAULT_DOCK_LAYOUTS.size());
|
||||
md5.Update(&layout_count, sizeof(layout_count));
|
||||
|
||||
for (const DefaultDockLayout& layout : DEFAULT_DOCK_LAYOUTS)
|
||||
hashDefaultLayout(layout, md5);
|
||||
|
||||
u8 digest[16];
|
||||
md5.Final(digest);
|
||||
hash = fmt::format(
|
||||
"{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
|
||||
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7],
|
||||
digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
void DockTables::hashDefaultLayout(const DefaultDockLayout& layout, MD5Digest& md5)
|
||||
{
|
||||
u32 layout_name_size = static_cast<u32>(layout.name.size());
|
||||
md5.Update(&layout_name_size, sizeof(layout_name_size));
|
||||
md5.Update(layout.name.data(), layout_name_size);
|
||||
|
||||
const char* cpu_name = DebugInterface::cpuName(layout.cpu);
|
||||
u32 cpu_name_size = static_cast<u32>(strlen(cpu_name));
|
||||
md5.Update(&cpu_name_size, sizeof(cpu_name_size));
|
||||
md5.Update(cpu_name, cpu_name_size);
|
||||
|
||||
u32 group_count = static_cast<u32>(layout.groups.size());
|
||||
md5.Update(&group_count, sizeof(group_count));
|
||||
|
||||
for (const DefaultDockGroupDescription& group : layout.groups)
|
||||
hashDefaultGroup(group, md5);
|
||||
|
||||
u32 widget_count = static_cast<u32>(layout.widgets.size());
|
||||
md5.Update(&widget_count, sizeof(widget_count));
|
||||
|
||||
for (const DefaultDockWidgetDescription& widget : layout.widgets)
|
||||
hashDefaultDockWidget(widget, md5);
|
||||
|
||||
u32 toolbar_count = static_cast<u32>(layout.toolbars.size());
|
||||
md5.Update(&toolbar_count, sizeof(toolbar_count));
|
||||
for (const std::string& toolbar : layout.toolbars)
|
||||
{
|
||||
u32 toolbar_size = toolbar.size();
|
||||
md5.Update(&toolbar_size, sizeof(toolbar_size));
|
||||
md5.Update(toolbar.data(), toolbar.size());
|
||||
}
|
||||
}
|
||||
|
||||
void DockTables::hashDefaultGroup(const DefaultDockGroupDescription& group, MD5Digest& md5)
|
||||
{
|
||||
// This is inline here so that it's obvious that changing it will affect the
|
||||
// result of the hash.
|
||||
const char* location = "";
|
||||
switch (group.location)
|
||||
{
|
||||
case KDDockWidgets::Location_None:
|
||||
location = "none";
|
||||
break;
|
||||
case KDDockWidgets::Location_OnLeft:
|
||||
location = "left";
|
||||
break;
|
||||
case KDDockWidgets::Location_OnTop:
|
||||
location = "top";
|
||||
break;
|
||||
case KDDockWidgets::Location_OnRight:
|
||||
location = "right";
|
||||
break;
|
||||
case KDDockWidgets::Location_OnBottom:
|
||||
location = "bottom";
|
||||
break;
|
||||
}
|
||||
|
||||
u32 location_size = static_cast<u32>(strlen(location));
|
||||
md5.Update(&location_size, sizeof(location_size));
|
||||
md5.Update(location, location_size);
|
||||
|
||||
u32 parent = static_cast<u32>(group.parent);
|
||||
md5.Update(&parent, sizeof(parent));
|
||||
}
|
||||
|
||||
void DockTables::hashDefaultDockWidget(const DefaultDockWidgetDescription& widget, MD5Digest& md5)
|
||||
{
|
||||
u32 type_size = static_cast<u32>(widget.type.size());
|
||||
md5.Update(&type_size, sizeof(type_size));
|
||||
md5.Update(widget.type.data(), type_size);
|
||||
|
||||
u32 group = static_cast<u32>(widget.group);
|
||||
md5.Update(&group, sizeof(group));
|
||||
}
|
||||
75
pcsx2-qt/Debugger/Docking/DockTables.h
Normal file
75
pcsx2-qt/Debugger/Docking/DockTables.h
Normal file
@@ -0,0 +1,75 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DockUtils.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
#include <kddockwidgets/KDDockWidgets.h>
|
||||
|
||||
class MD5Digest;
|
||||
|
||||
class DebuggerWidget;
|
||||
struct DebuggerWidgetParameters;
|
||||
|
||||
namespace DockTables
|
||||
{
|
||||
struct DebuggerWidgetDescription
|
||||
{
|
||||
DebuggerWidget* (*create_widget)(const DebuggerWidgetParameters& parameters);
|
||||
|
||||
// The untranslated string displayed as the dock widget tab text.
|
||||
const char* display_name;
|
||||
|
||||
// This is used to determine which group dock widgets of this type are
|
||||
// added to when they're opened from the Windows menu.
|
||||
DockUtils::PreferredLocation preferred_location;
|
||||
};
|
||||
|
||||
extern const std::map<std::string, DebuggerWidgetDescription> DEBUGGER_WIDGETS;
|
||||
|
||||
enum class DefaultDockGroup
|
||||
{
|
||||
ROOT = -1,
|
||||
TOP_RIGHT = 0,
|
||||
BOTTOM = 1,
|
||||
TOP_LEFT = 2
|
||||
};
|
||||
|
||||
struct DefaultDockGroupDescription
|
||||
{
|
||||
KDDockWidgets::Location location;
|
||||
DefaultDockGroup parent;
|
||||
};
|
||||
|
||||
extern const std::vector<DefaultDockGroupDescription> DEFAULT_DOCK_GROUPS;
|
||||
|
||||
struct DefaultDockWidgetDescription
|
||||
{
|
||||
std::string type;
|
||||
DefaultDockGroup group;
|
||||
};
|
||||
|
||||
struct DefaultDockLayout
|
||||
{
|
||||
std::string name;
|
||||
BreakPointCpu cpu;
|
||||
std::vector<DefaultDockGroupDescription> groups;
|
||||
std::vector<DefaultDockWidgetDescription> widgets;
|
||||
std::set<std::string> toolbars;
|
||||
};
|
||||
|
||||
extern const std::vector<DefaultDockLayout> DEFAULT_DOCK_LAYOUTS;
|
||||
|
||||
const DefaultDockLayout* defaultLayout(const std::string& name);
|
||||
|
||||
// This is used to determine if the user has updated and we need to recreate
|
||||
// the default layouts.
|
||||
const std::string& hashDefaultLayouts();
|
||||
|
||||
void hashDefaultLayout(const DefaultDockLayout& layout, MD5Digest& md5);
|
||||
void hashDefaultGroup(const DefaultDockGroupDescription& group, MD5Digest& md5);
|
||||
void hashDefaultDockWidget(const DefaultDockWidgetDescription& widget, MD5Digest& md5);
|
||||
} // namespace DockTables
|
||||
98
pcsx2-qt/Debugger/Docking/DockUtils.cpp
Normal file
98
pcsx2-qt/Debugger/Docking/DockUtils.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "DockUtils.h"
|
||||
|
||||
#include <kddockwidgets/Config.h>
|
||||
#include <kddockwidgets/core/DockRegistry.h>
|
||||
#include <kddockwidgets/core/Group.h>
|
||||
#include <kddockwidgets/qtwidgets/DockWidget.h>
|
||||
#include <kddockwidgets/qtwidgets/Group.h>
|
||||
|
||||
DockUtils::DockWidgetPair DockUtils::dockWidgetFromName(const QString& unique_name)
|
||||
{
|
||||
KDDockWidgets::Vector<QString> names{unique_name};
|
||||
KDDockWidgets::Vector<KDDockWidgets::Core::DockWidget*> dock_widgets =
|
||||
KDDockWidgets::DockRegistry::self()->dockWidgets(names);
|
||||
if (dock_widgets.size() != 1 || !dock_widgets[0])
|
||||
return {};
|
||||
|
||||
return {dock_widgets[0], static_cast<KDDockWidgets::QtWidgets::DockWidget*>(dock_widgets[0]->view())};
|
||||
}
|
||||
|
||||
void DockUtils::insertDockWidgetAtPreferredLocation(
|
||||
KDDockWidgets::Core::DockWidget* dock_widget,
|
||||
PreferredLocation location,
|
||||
KDDockWidgets::QtWidgets::MainWindow* window)
|
||||
{
|
||||
int width = window->width();
|
||||
int height = window->height();
|
||||
int half_width = width / 2;
|
||||
int half_height = height / 2;
|
||||
|
||||
QPoint preferred_location;
|
||||
switch (location)
|
||||
{
|
||||
case DockUtils::TOP_LEFT:
|
||||
preferred_location = {0, 0};
|
||||
break;
|
||||
case DockUtils::TOP_MIDDLE:
|
||||
preferred_location = {half_width, 0};
|
||||
break;
|
||||
case DockUtils::TOP_RIGHT:
|
||||
preferred_location = {width, 0};
|
||||
break;
|
||||
case DockUtils::MIDDLE_LEFT:
|
||||
preferred_location = {0, half_height};
|
||||
break;
|
||||
case DockUtils::MIDDLE_MIDDLE:
|
||||
preferred_location = {half_width, half_height};
|
||||
break;
|
||||
case DockUtils::MIDDLE_RIGHT:
|
||||
preferred_location = {width, half_height};
|
||||
break;
|
||||
case DockUtils::BOTTOM_LEFT:
|
||||
preferred_location = {0, height};
|
||||
break;
|
||||
case DockUtils::BOTTOM_MIDDLE:
|
||||
preferred_location = {half_width, height};
|
||||
break;
|
||||
case DockUtils::BOTTOM_RIGHT:
|
||||
preferred_location = {width, height};
|
||||
break;
|
||||
}
|
||||
|
||||
// Find the dock group which is closest to the preferred location.
|
||||
KDDockWidgets::Core::Group* best_group = nullptr;
|
||||
int best_distance_squared = 0;
|
||||
|
||||
for (KDDockWidgets::Core::Group* group_controller : KDDockWidgets::DockRegistry::self()->groups())
|
||||
{
|
||||
if (group_controller->isFloating())
|
||||
continue;
|
||||
|
||||
auto group = static_cast<KDDockWidgets::QtWidgets::Group*>(group_controller->view());
|
||||
|
||||
QPoint local_midpoint = group->pos() + QPoint(group->width() / 2, group->height() / 2);
|
||||
QPoint midpoint = group->mapTo(window, local_midpoint);
|
||||
QPoint delta = midpoint - preferred_location;
|
||||
int distance_squared = delta.x() * delta.x() + delta.y() * delta.y();
|
||||
|
||||
if (!best_group || distance_squared < best_distance_squared)
|
||||
{
|
||||
best_group = group_controller;
|
||||
best_distance_squared = distance_squared;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_group && best_group->dockWidgetCount() > 0)
|
||||
{
|
||||
KDDockWidgets::Core::DockWidget* other_dock_widget = best_group->dockWidgetAt(0);
|
||||
other_dock_widget->addDockWidgetAsTab(dock_widget);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dock_view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(dock_widget->view());
|
||||
window->addDockWidget(dock_view, KDDockWidgets::Location_OnTop);
|
||||
}
|
||||
}
|
||||
40
pcsx2-qt/Debugger/Docking/DockUtils.h
Normal file
40
pcsx2-qt/Debugger/Docking/DockUtils.h
Normal file
@@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kddockwidgets/KDDockWidgets.h>
|
||||
#include <kddockwidgets/core/DockWidget.h>
|
||||
#include <kddockwidgets/qtwidgets/MainWindow.h>
|
||||
|
||||
namespace DockUtils
|
||||
{
|
||||
inline const constexpr int MAX_LAYOUT_NAME_SIZE = 40;
|
||||
inline const constexpr int MAX_DOCK_WIDGET_NAME_SIZE = 40;
|
||||
|
||||
struct DockWidgetPair
|
||||
{
|
||||
KDDockWidgets::Core::DockWidget* controller = nullptr;
|
||||
KDDockWidgets::QtWidgets::DockWidget* view = nullptr;
|
||||
};
|
||||
|
||||
DockWidgetPair dockWidgetFromName(const QString& unique_name);
|
||||
|
||||
enum PreferredLocation
|
||||
{
|
||||
TOP_LEFT,
|
||||
TOP_MIDDLE,
|
||||
TOP_RIGHT,
|
||||
MIDDLE_LEFT,
|
||||
MIDDLE_MIDDLE,
|
||||
MIDDLE_RIGHT,
|
||||
BOTTOM_LEFT,
|
||||
BOTTOM_MIDDLE,
|
||||
BOTTOM_RIGHT
|
||||
};
|
||||
|
||||
void insertDockWidgetAtPreferredLocation(
|
||||
KDDockWidgets::Core::DockWidget* dock_widget,
|
||||
PreferredLocation location,
|
||||
KDDockWidgets::QtWidgets::MainWindow* window);
|
||||
} // namespace DockUtils
|
||||
303
pcsx2-qt/Debugger/Docking/DockViews.cpp
Normal file
303
pcsx2-qt/Debugger/Docking/DockViews.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "DockViews.h"
|
||||
|
||||
#include "QtUtils.h"
|
||||
#include "Debugger/DebuggerWidget.h"
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
#include "Debugger/Docking/DockManager.h"
|
||||
#include "Debugger/Docking/DropIndicators.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
#include <kddockwidgets/Config.h>
|
||||
#include <kddockwidgets/core/TabBar.h>
|
||||
#include <kddockwidgets/qtwidgets/views/DockWidget.h>
|
||||
|
||||
#include <QtGui/QActionGroup>
|
||||
#include <QtGui/QPalette>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QMenu>
|
||||
|
||||
KDDockWidgets::Core::View* DockViewFactory::createDockWidget(
|
||||
const QString& unique_name,
|
||||
KDDockWidgets::DockWidgetOptions options,
|
||||
KDDockWidgets::LayoutSaverOptions layout_saver_options,
|
||||
Qt::WindowFlags window_flags) const
|
||||
{
|
||||
return new DockWidget(unique_name, options, layout_saver_options, window_flags);
|
||||
}
|
||||
|
||||
KDDockWidgets::Core::View* DockViewFactory::createTitleBar(
|
||||
KDDockWidgets::Core::TitleBar* controller,
|
||||
KDDockWidgets::Core::View* parent) const
|
||||
{
|
||||
return new DockTitleBar(controller, parent);
|
||||
}
|
||||
|
||||
KDDockWidgets::Core::View* DockViewFactory::createStack(
|
||||
KDDockWidgets::Core::Stack* controller,
|
||||
KDDockWidgets::Core::View* parent) const
|
||||
{
|
||||
return new DockStack(controller, KDDockWidgets::QtCommon::View_qt::asQWidget(parent));
|
||||
}
|
||||
|
||||
KDDockWidgets::Core::View* DockViewFactory::createTabBar(
|
||||
KDDockWidgets::Core::TabBar* tabBar,
|
||||
KDDockWidgets::Core::View* parent) const
|
||||
{
|
||||
return new DockTabBar(tabBar, KDDockWidgets::QtCommon::View_qt::asQWidget(parent));
|
||||
}
|
||||
|
||||
KDDockWidgets::Core::ClassicIndicatorWindowViewInterface* DockViewFactory::createClassicIndicatorWindow(
|
||||
KDDockWidgets::Core::ClassicDropIndicatorOverlay* classic_indicators,
|
||||
KDDockWidgets::Core::View* parent) const
|
||||
{
|
||||
return new DockDropIndicatorProxy(classic_indicators);
|
||||
}
|
||||
|
||||
KDDockWidgets::Core::ClassicIndicatorWindowViewInterface* DockViewFactory::createFallbackClassicIndicatorWindow(
|
||||
KDDockWidgets::Core::ClassicDropIndicatorOverlay* classic_indicators,
|
||||
KDDockWidgets::Core::View* parent) const
|
||||
{
|
||||
return KDDockWidgets::QtWidgets::ViewFactory::createClassicIndicatorWindow(classic_indicators, parent);
|
||||
}
|
||||
|
||||
KDDockWidgets::Core::View* DockViewFactory::createSegmentedDropIndicatorOverlayView(
|
||||
KDDockWidgets::Core::SegmentedDropIndicatorOverlay* controller,
|
||||
KDDockWidgets::Core::View* parent) const
|
||||
{
|
||||
return new DockSegmentedDropIndicatorOverlay(controller, KDDockWidgets::QtCommon::View_qt::asQWidget(parent));
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
||||
DockWidget::DockWidget(
|
||||
const QString& unique_name,
|
||||
KDDockWidgets::DockWidgetOptions options,
|
||||
KDDockWidgets::LayoutSaverOptions layout_saver_options,
|
||||
Qt::WindowFlags window_flags)
|
||||
: KDDockWidgets::QtWidgets::DockWidget(unique_name, options, layout_saver_options, window_flags)
|
||||
{
|
||||
connect(this, &DockWidget::isOpenChanged, this, &DockWidget::openStateChanged);
|
||||
}
|
||||
|
||||
void DockWidget::openStateChanged(bool open)
|
||||
{
|
||||
// The LayoutSaver class will close a bunch of dock widgets. We only want to
|
||||
// delete the dock widgets when they're being closed by the user.
|
||||
if (KDDockWidgets::LayoutSaver::restoreInProgress())
|
||||
return;
|
||||
|
||||
if (!open && g_debugger_window)
|
||||
g_debugger_window->dockManager().destroyDebuggerWidget(uniqueName());
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
||||
DockTitleBar::DockTitleBar(KDDockWidgets::Core::TitleBar* controller, KDDockWidgets::Core::View* parent)
|
||||
: KDDockWidgets::QtWidgets::TitleBar(controller, parent)
|
||||
{
|
||||
}
|
||||
|
||||
void DockTitleBar::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
if (g_debugger_window && !g_debugger_window->dockManager().isLayoutLocked())
|
||||
KDDockWidgets::QtWidgets::TitleBar::mouseDoubleClickEvent(event);
|
||||
else
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
||||
DockStack::DockStack(KDDockWidgets::Core::Stack* controller, QWidget* parent)
|
||||
: KDDockWidgets::QtWidgets::Stack(controller, parent)
|
||||
{
|
||||
}
|
||||
|
||||
void DockStack::init()
|
||||
{
|
||||
KDDockWidgets::QtWidgets::Stack::init();
|
||||
|
||||
if (g_debugger_window)
|
||||
{
|
||||
bool locked = g_debugger_window->dockManager().isLayoutLocked();
|
||||
setTabsClosable(!locked);
|
||||
}
|
||||
}
|
||||
|
||||
void DockStack::mouseDoubleClickEvent(QMouseEvent* ev)
|
||||
{
|
||||
if (g_debugger_window && !g_debugger_window->dockManager().isLayoutLocked())
|
||||
KDDockWidgets::QtWidgets::Stack::mouseDoubleClickEvent(ev);
|
||||
else
|
||||
ev->ignore();
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
||||
DockTabBar::DockTabBar(KDDockWidgets::Core::TabBar* controller, QWidget* parent)
|
||||
: KDDockWidgets::QtWidgets::TabBar(controller, parent)
|
||||
{
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(this, &DockTabBar::customContextMenuRequested, this, &DockTabBar::openContextMenu);
|
||||
}
|
||||
|
||||
void DockTabBar::openContextMenu(QPoint pos)
|
||||
{
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
int tab_index = tabAt(pos);
|
||||
|
||||
// Filter out the placeholder widget displayed when there are no layouts.
|
||||
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
size_t dock_widgets_of_type = g_debugger_window->dockManager().countDebuggerWidgetsOfType(
|
||||
widget->metaObject()->className());
|
||||
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QAction* rename_action = menu->addAction(tr("Rename"));
|
||||
connect(rename_action, &QAction::triggered, this, [this, tab_index]() {
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
bool ok;
|
||||
QString new_name = QInputDialog::getText(
|
||||
this, tr("Rename Window"), tr("New name:"), QLineEdit::Normal, widget->displayNameWithoutSuffix(), &ok);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
if (!widget->setCustomDisplayName(new_name))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid Name"), tr("The specified name is too long."));
|
||||
return;
|
||||
}
|
||||
|
||||
g_debugger_window->dockManager().updateDockWidgetTitles();
|
||||
});
|
||||
|
||||
QAction* reset_name_action = menu->addAction(tr("Reset Name"));
|
||||
reset_name_action->setEnabled(!widget->customDisplayName().isEmpty());
|
||||
connect(reset_name_action, &QAction::triggered, this, [this, tab_index] {
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
widget->setCustomDisplayName(QString());
|
||||
g_debugger_window->dockManager().updateDockWidgetTitles();
|
||||
});
|
||||
|
||||
QAction* primary_action = menu->addAction(tr("Primary"));
|
||||
primary_action->setCheckable(true);
|
||||
primary_action->setChecked(widget->isPrimary());
|
||||
primary_action->setEnabled(dock_widgets_of_type > 1);
|
||||
connect(primary_action, &QAction::triggered, this, [this, tab_index](bool checked) {
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
g_debugger_window->dockManager().setPrimaryDebuggerWidget(widget, checked);
|
||||
});
|
||||
|
||||
QMenu* set_target_menu = menu->addMenu(tr("Set Target"));
|
||||
QActionGroup* set_target_group = new QActionGroup(menu);
|
||||
set_target_group->setExclusive(true);
|
||||
|
||||
for (BreakPointCpu cpu : DEBUG_CPUS)
|
||||
{
|
||||
const char* long_cpu_name = DebugInterface::longCpuName(cpu);
|
||||
const char* cpu_name = DebugInterface::cpuName(cpu);
|
||||
QString text = QString("%1 (%2)").arg(long_cpu_name).arg(cpu_name);
|
||||
|
||||
QAction* cpu_action = set_target_menu->addAction(text);
|
||||
cpu_action->setCheckable(true);
|
||||
cpu_action->setChecked(widget->cpuOverride().has_value() && *widget->cpuOverride() == cpu);
|
||||
connect(cpu_action, &QAction::triggered, this, [this, tab_index, cpu]() {
|
||||
setCpuOverrideForTab(tab_index, cpu);
|
||||
});
|
||||
set_target_group->addAction(cpu_action);
|
||||
}
|
||||
|
||||
set_target_menu->addSeparator();
|
||||
|
||||
QAction* inherit_action = set_target_menu->addAction(tr("Inherit From Layout"));
|
||||
inherit_action->setCheckable(true);
|
||||
inherit_action->setChecked(!widget->cpuOverride().has_value());
|
||||
connect(inherit_action, &QAction::triggered, this, [this, tab_index]() {
|
||||
setCpuOverrideForTab(tab_index, std::nullopt);
|
||||
});
|
||||
set_target_group->addAction(inherit_action);
|
||||
|
||||
QAction* close_action = menu->addAction(tr("Close"));
|
||||
connect(close_action, &QAction::triggered, this, [this, tab_index]() {
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
g_debugger_window->dockManager().destroyDebuggerWidget(widget->uniqueName());
|
||||
});
|
||||
|
||||
menu->popup(mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void DockTabBar::setCpuOverrideForTab(int tab_index, std::optional<BreakPointCpu> cpu_override)
|
||||
{
|
||||
if (!g_debugger_window)
|
||||
return;
|
||||
|
||||
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
if (!widget->setCpuOverride(cpu_override))
|
||||
g_debugger_window->dockManager().recreateDebuggerWidget(view->uniqueName());
|
||||
|
||||
g_debugger_window->dockManager().updateDockWidgetTitles();
|
||||
}
|
||||
|
||||
DockTabBar::WidgetsFromTabIndexResult DockTabBar::widgetsFromTabIndex(int tab_index)
|
||||
{
|
||||
KDDockWidgets::Core::TabBar* tab_bar_controller = asController<KDDockWidgets::Core::TabBar>();
|
||||
if (!tab_bar_controller)
|
||||
return {};
|
||||
|
||||
KDDockWidgets::Core::DockWidget* dock_controller = tab_bar_controller->dockWidgetAt(tab_index);
|
||||
if (!dock_controller)
|
||||
return {};
|
||||
|
||||
auto dock_view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(dock_controller->view());
|
||||
|
||||
DebuggerWidget* widget = qobject_cast<DebuggerWidget*>(dock_view->widget());
|
||||
if (!widget)
|
||||
return {};
|
||||
|
||||
return {widget, dock_controller, dock_view};
|
||||
}
|
||||
|
||||
void DockTabBar::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
if (g_debugger_window && !g_debugger_window->dockManager().isLayoutLocked())
|
||||
KDDockWidgets::QtWidgets::TabBar::mouseDoubleClickEvent(event);
|
||||
else
|
||||
event->ignore();
|
||||
}
|
||||
113
pcsx2-qt/Debugger/Docking/DockViews.h
Normal file
113
pcsx2-qt/Debugger/Docking/DockViews.h
Normal file
@@ -0,0 +1,113 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
#include <kddockwidgets/qtwidgets/ViewFactory.h>
|
||||
#include <kddockwidgets/qtwidgets/views/DockWidget.h>
|
||||
#include <kddockwidgets/qtwidgets/views/Stack.h>
|
||||
#include <kddockwidgets/qtwidgets/views/TitleBar.h>
|
||||
#include <kddockwidgets/qtwidgets/views/TabBar.h>
|
||||
|
||||
class DebuggerWidget;
|
||||
class DockManager;
|
||||
|
||||
class DockViewFactory : public KDDockWidgets::QtWidgets::ViewFactory
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KDDockWidgets::Core::View* createDockWidget(
|
||||
const QString& unique_name,
|
||||
KDDockWidgets::DockWidgetOptions options = {},
|
||||
KDDockWidgets::LayoutSaverOptions layout_saver_options = {},
|
||||
Qt::WindowFlags window_flags = {}) const override;
|
||||
|
||||
KDDockWidgets::Core::View* createTitleBar(
|
||||
KDDockWidgets::Core::TitleBar* controller,
|
||||
KDDockWidgets::Core::View* parent) const override;
|
||||
|
||||
KDDockWidgets::Core::View* createStack(
|
||||
KDDockWidgets::Core::Stack* controller,
|
||||
KDDockWidgets::Core::View* parent) const override;
|
||||
|
||||
KDDockWidgets::Core::View* createTabBar(
|
||||
KDDockWidgets::Core::TabBar* tabBar,
|
||||
KDDockWidgets::Core::View* parent) const override;
|
||||
|
||||
KDDockWidgets::Core::ClassicIndicatorWindowViewInterface* createClassicIndicatorWindow(
|
||||
KDDockWidgets::Core::ClassicDropIndicatorOverlay* classic_indicators,
|
||||
KDDockWidgets::Core::View* parent) const override;
|
||||
|
||||
KDDockWidgets::Core::ClassicIndicatorWindowViewInterface* createFallbackClassicIndicatorWindow(
|
||||
KDDockWidgets::Core::ClassicDropIndicatorOverlay* classic_indicators,
|
||||
KDDockWidgets::Core::View* parent) const;
|
||||
|
||||
KDDockWidgets::Core::View* createSegmentedDropIndicatorOverlayView(
|
||||
KDDockWidgets::Core::SegmentedDropIndicatorOverlay* controller,
|
||||
KDDockWidgets::Core::View* parent) const override;
|
||||
};
|
||||
|
||||
class DockWidget : public KDDockWidgets::QtWidgets::DockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DockWidget(
|
||||
const QString& unique_name,
|
||||
KDDockWidgets::DockWidgetOptions options,
|
||||
KDDockWidgets::LayoutSaverOptions layout_saver_options,
|
||||
Qt::WindowFlags window_flags);
|
||||
|
||||
protected:
|
||||
void openStateChanged(bool open);
|
||||
};
|
||||
|
||||
class DockTitleBar : public KDDockWidgets::QtWidgets::TitleBar
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DockTitleBar(KDDockWidgets::Core::TitleBar* controller, KDDockWidgets::Core::View* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||
};
|
||||
|
||||
class DockStack : public KDDockWidgets::QtWidgets::Stack
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DockStack(KDDockWidgets::Core::Stack* controller, QWidget* parent = nullptr);
|
||||
|
||||
void init() override;
|
||||
|
||||
protected:
|
||||
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||
};
|
||||
|
||||
class DockTabBar : public KDDockWidgets::QtWidgets::TabBar
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DockTabBar(KDDockWidgets::Core::TabBar* controller, QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void openContextMenu(QPoint pos);
|
||||
|
||||
struct WidgetsFromTabIndexResult
|
||||
{
|
||||
DebuggerWidget* debugger_widget = nullptr;
|
||||
KDDockWidgets::Core::DockWidget* controller = nullptr;
|
||||
KDDockWidgets::QtWidgets::DockWidget* view = nullptr;
|
||||
};
|
||||
|
||||
void setCpuOverrideForTab(int tab_index, std::optional<BreakPointCpu> cpu_override);
|
||||
WidgetsFromTabIndexResult widgetsFromTabIndex(int tab_index);
|
||||
|
||||
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||
};
|
||||
571
pcsx2-qt/Debugger/Docking/DropIndicators.cpp
Normal file
571
pcsx2-qt/Debugger/Docking/DropIndicators.cpp
Normal file
@@ -0,0 +1,571 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "DropIndicators.h"
|
||||
|
||||
#include "QtUtils.h"
|
||||
#include "Debugger/Docking/DockViews.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
|
||||
#include <kddockwidgets/Config.h>
|
||||
#include <kddockwidgets/core/Group.h>
|
||||
#include <kddockwidgets/core/indicators/SegmentedDropIndicatorOverlay.h>
|
||||
#include <kddockwidgets/qtwidgets/ViewFactory.h>
|
||||
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
static std::pair<QColor, QColor> pickNiceColours(const QPalette& palette, bool hovered)
|
||||
{
|
||||
QColor fill = palette.highlight().color();
|
||||
QColor outline = palette.highlight().color();
|
||||
|
||||
if (QtUtils::IsLightTheme(palette))
|
||||
{
|
||||
fill = fill.darker(200);
|
||||
outline = outline.darker(200);
|
||||
}
|
||||
else
|
||||
{
|
||||
fill = fill.lighter(200);
|
||||
outline = outline.lighter(200);
|
||||
}
|
||||
|
||||
fill.setAlpha(200);
|
||||
outline.setAlpha(255);
|
||||
|
||||
if (!hovered)
|
||||
{
|
||||
fill.setAlpha(fill.alpha() / 2);
|
||||
outline.setAlpha(outline.alpha() / 2);
|
||||
}
|
||||
|
||||
return {fill, outline};
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
||||
DockDropIndicatorProxy::DockDropIndicatorProxy(KDDockWidgets::Core::ClassicDropIndicatorOverlay* classic_indicators)
|
||||
: m_classic_indicators(classic_indicators)
|
||||
{
|
||||
recreateWindowIfNecessary();
|
||||
}
|
||||
|
||||
DockDropIndicatorProxy::~DockDropIndicatorProxy()
|
||||
{
|
||||
delete m_window;
|
||||
delete m_fallback_window;
|
||||
}
|
||||
|
||||
void DockDropIndicatorProxy::setObjectName(const QString& name)
|
||||
{
|
||||
window()->setObjectName(name);
|
||||
}
|
||||
|
||||
KDDockWidgets::DropLocation DockDropIndicatorProxy::hover(QPoint globalPos)
|
||||
{
|
||||
return window()->hover(globalPos);
|
||||
}
|
||||
|
||||
QPoint DockDropIndicatorProxy::posForIndicator(KDDockWidgets::DropLocation loc) const
|
||||
{
|
||||
return window()->posForIndicator(loc);
|
||||
}
|
||||
|
||||
void DockDropIndicatorProxy::updatePositions()
|
||||
{
|
||||
// Check if a compositor is running whenever a drag starts.
|
||||
recreateWindowIfNecessary();
|
||||
|
||||
window()->updatePositions();
|
||||
}
|
||||
|
||||
void DockDropIndicatorProxy::raise()
|
||||
{
|
||||
window()->raise();
|
||||
}
|
||||
|
||||
void DockDropIndicatorProxy::setVisible(bool visible)
|
||||
{
|
||||
window()->setVisible(visible);
|
||||
}
|
||||
|
||||
void DockDropIndicatorProxy::resize(QSize size)
|
||||
{
|
||||
window()->resize(size);
|
||||
}
|
||||
|
||||
void DockDropIndicatorProxy::setGeometry(QRect rect)
|
||||
{
|
||||
window()->setGeometry(rect);
|
||||
}
|
||||
|
||||
bool DockDropIndicatorProxy::isWindow() const
|
||||
{
|
||||
return window()->isWindow();
|
||||
}
|
||||
|
||||
void DockDropIndicatorProxy::updateIndicatorVisibility()
|
||||
{
|
||||
window()->updateIndicatorVisibility();
|
||||
}
|
||||
|
||||
KDDockWidgets::Core::ClassicIndicatorWindowViewInterface* DockDropIndicatorProxy::window()
|
||||
{
|
||||
if (!m_supports_compositing)
|
||||
{
|
||||
pxAssert(m_fallback_window);
|
||||
return m_fallback_window;
|
||||
}
|
||||
|
||||
pxAssert(m_window);
|
||||
return m_window;
|
||||
}
|
||||
|
||||
const KDDockWidgets::Core::ClassicIndicatorWindowViewInterface* DockDropIndicatorProxy::window() const
|
||||
{
|
||||
if (!m_supports_compositing)
|
||||
{
|
||||
pxAssert(m_fallback_window);
|
||||
return m_fallback_window;
|
||||
}
|
||||
|
||||
pxAssert(m_window);
|
||||
return m_window;
|
||||
}
|
||||
|
||||
void DockDropIndicatorProxy::recreateWindowIfNecessary()
|
||||
{
|
||||
bool supports_compositing = QtUtils::IsCompositorManagerRunning();
|
||||
if (supports_compositing == m_supports_compositing && (m_window || m_fallback_window))
|
||||
return;
|
||||
|
||||
m_supports_compositing = supports_compositing;
|
||||
|
||||
DockViewFactory* factory = static_cast<DockViewFactory*>(KDDockWidgets::Config::self().viewFactory());
|
||||
|
||||
if (supports_compositing)
|
||||
{
|
||||
if (!m_window)
|
||||
m_window = new DockDropIndicatorWindow(m_classic_indicators);
|
||||
|
||||
QWidget* old_window = dynamic_cast<QWidget*>(m_fallback_window);
|
||||
if (old_window)
|
||||
{
|
||||
m_window->setObjectName(old_window->objectName());
|
||||
m_window->setVisible(old_window->isVisible());
|
||||
m_window->setGeometry(old_window->geometry());
|
||||
}
|
||||
|
||||
delete m_fallback_window;
|
||||
m_fallback_window = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_fallback_window)
|
||||
m_fallback_window = factory->createFallbackClassicIndicatorWindow(m_classic_indicators, nullptr);
|
||||
|
||||
QWidget* old_window = dynamic_cast<QWidget*>(m_window);
|
||||
if (old_window)
|
||||
{
|
||||
m_window->setObjectName(old_window->objectName());
|
||||
m_window->setVisible(old_window->isVisible());
|
||||
m_window->setGeometry(old_window->geometry());
|
||||
}
|
||||
|
||||
delete m_window;
|
||||
m_window = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
||||
static const constexpr int IND_LEFT = 0;
|
||||
static const constexpr int IND_TOP = 1;
|
||||
static const constexpr int IND_RIGHT = 2;
|
||||
static const constexpr int IND_BOTTOM = 3;
|
||||
static const constexpr int IND_CENTER = 4;
|
||||
static const constexpr int IND_OUTER_LEFT = 5;
|
||||
static const constexpr int IND_OUTER_TOP = 6;
|
||||
static const constexpr int IND_OUTER_RIGHT = 7;
|
||||
static const constexpr int IND_OUTER_BOTTOM = 8;
|
||||
|
||||
static const constexpr int INDICATOR_SIZE = 40;
|
||||
static const constexpr int INDICATOR_MARGIN = 10;
|
||||
|
||||
static bool isWayland()
|
||||
{
|
||||
return KDDockWidgets::Core::Platform::instance()->displayType() ==
|
||||
KDDockWidgets::Core::Platform::DisplayType::Wayland;
|
||||
}
|
||||
|
||||
static QWidget* parentForIndicatorWindow(KDDockWidgets::Core::ClassicDropIndicatorOverlay* classic_indicators)
|
||||
{
|
||||
if (isWayland())
|
||||
return KDDockWidgets::QtCommon::View_qt::asQWidget(classic_indicators->view());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Qt::WindowFlags flagsForIndicatorWindow()
|
||||
{
|
||||
if (isWayland())
|
||||
return Qt::Widget;
|
||||
|
||||
return Qt::Tool | Qt::BypassWindowManagerHint;
|
||||
}
|
||||
|
||||
DockDropIndicatorWindow::DockDropIndicatorWindow(
|
||||
KDDockWidgets::Core::ClassicDropIndicatorOverlay* classic_indicators)
|
||||
: QWidget(parentForIndicatorWindow(classic_indicators), flagsForIndicatorWindow())
|
||||
, m_classic_indicators(classic_indicators)
|
||||
, m_indicators({
|
||||
/* [IND_LEFT] = */ new DockDropIndicator(KDDockWidgets::DropLocation_Left, this),
|
||||
/* [IND_TOP] = */ new DockDropIndicator(KDDockWidgets::DropLocation_Top, this),
|
||||
/* [IND_RIGHT] = */ new DockDropIndicator(KDDockWidgets::DropLocation_Right, this),
|
||||
/* [IND_BOTTOM] = */ new DockDropIndicator(KDDockWidgets::DropLocation_Bottom, this),
|
||||
/* [IND_CENTER] = */ new DockDropIndicator(KDDockWidgets::DropLocation_Center, this),
|
||||
/* [IND_OUTER_LEFT] = */ new DockDropIndicator(KDDockWidgets::DropLocation_OutterLeft, this),
|
||||
/* [IND_OUTER_TOP] = */ new DockDropIndicator(KDDockWidgets::DropLocation_OutterTop, this),
|
||||
/* [IND_OUTER_RIGHT] = */ new DockDropIndicator(KDDockWidgets::DropLocation_OutterRight, this),
|
||||
/* [IND_OUTER_BOTTOM] = */ new DockDropIndicator(KDDockWidgets::DropLocation_OutterBottom, this),
|
||||
})
|
||||
{
|
||||
setWindowFlag(Qt::FramelessWindowHint, true);
|
||||
|
||||
if (KDDockWidgets::Config::self().flags() & KDDockWidgets::Config::Flag_KeepAboveIfNotUtilityWindow)
|
||||
setWindowFlag(Qt::WindowStaysOnTopHint, true);
|
||||
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
}
|
||||
|
||||
void DockDropIndicatorWindow::setObjectName(const QString& name)
|
||||
{
|
||||
QWidget::setObjectName(name);
|
||||
}
|
||||
|
||||
KDDockWidgets::DropLocation DockDropIndicatorWindow::hover(QPoint globalPos)
|
||||
{
|
||||
KDDockWidgets::DropLocation result = KDDockWidgets::DropLocation_None;
|
||||
|
||||
for (DockDropIndicator* indicator : m_indicators)
|
||||
{
|
||||
if (indicator->isVisible())
|
||||
{
|
||||
bool hovered = indicator->rect().contains(indicator->mapFromGlobal(globalPos));
|
||||
if (hovered != indicator->hovered)
|
||||
{
|
||||
indicator->hovered = hovered;
|
||||
indicator->update();
|
||||
}
|
||||
|
||||
if (hovered)
|
||||
result = indicator->location;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QPoint DockDropIndicatorWindow::posForIndicator(KDDockWidgets::DropLocation loc) const
|
||||
{
|
||||
for (DockDropIndicator* indicator : m_indicators)
|
||||
if (indicator->location == loc)
|
||||
return indicator->mapToGlobal(indicator->rect().center());
|
||||
|
||||
return QPoint();
|
||||
}
|
||||
|
||||
void DockDropIndicatorWindow::updatePositions()
|
||||
{
|
||||
DockDropIndicator* left = m_indicators[IND_LEFT];
|
||||
DockDropIndicator* top = m_indicators[IND_TOP];
|
||||
DockDropIndicator* right = m_indicators[IND_RIGHT];
|
||||
DockDropIndicator* bottom = m_indicators[IND_BOTTOM];
|
||||
DockDropIndicator* center = m_indicators[IND_CENTER];
|
||||
DockDropIndicator* outer_left = m_indicators[IND_OUTER_LEFT];
|
||||
DockDropIndicator* outer_top = m_indicators[IND_OUTER_TOP];
|
||||
DockDropIndicator* outer_right = m_indicators[IND_OUTER_RIGHT];
|
||||
DockDropIndicator* outer_bottom = m_indicators[IND_OUTER_BOTTOM];
|
||||
|
||||
QRect r = rect();
|
||||
int half_indicator_width = INDICATOR_SIZE / 2;
|
||||
|
||||
outer_left->move(r.x() + INDICATOR_MARGIN, r.center().y() - half_indicator_width);
|
||||
outer_bottom->move(r.center().x() - half_indicator_width, r.y() + height() - INDICATOR_SIZE - INDICATOR_MARGIN);
|
||||
outer_top->move(r.center().x() - half_indicator_width, r.y() + INDICATOR_MARGIN);
|
||||
outer_right->move(r.x() + width() - INDICATOR_SIZE - INDICATOR_MARGIN, r.center().y() - half_indicator_width);
|
||||
|
||||
KDDockWidgets::Core::Group* hovered_group = m_classic_indicators->hoveredGroup();
|
||||
if (hovered_group)
|
||||
{
|
||||
QRect hoveredRect = hovered_group->view()->geometry();
|
||||
center->move(r.topLeft() + hoveredRect.center() - QPoint(half_indicator_width, half_indicator_width));
|
||||
top->move(center->pos() - QPoint(0, INDICATOR_SIZE + INDICATOR_MARGIN));
|
||||
right->move(center->pos() + QPoint(INDICATOR_SIZE + INDICATOR_MARGIN, 0));
|
||||
bottom->move(center->pos() + QPoint(0, INDICATOR_SIZE + INDICATOR_MARGIN));
|
||||
left->move(center->pos() - QPoint(INDICATOR_SIZE + INDICATOR_MARGIN, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void DockDropIndicatorWindow::raise()
|
||||
{
|
||||
QWidget::raise();
|
||||
}
|
||||
|
||||
void DockDropIndicatorWindow::setVisible(bool is)
|
||||
{
|
||||
QWidget::setVisible(is);
|
||||
}
|
||||
|
||||
void DockDropIndicatorWindow::resize(QSize size)
|
||||
{
|
||||
QWidget::resize(size);
|
||||
}
|
||||
|
||||
void DockDropIndicatorWindow::setGeometry(QRect rect)
|
||||
{
|
||||
QWidget::setGeometry(rect);
|
||||
}
|
||||
|
||||
bool DockDropIndicatorWindow::isWindow() const
|
||||
{
|
||||
return QWidget::isWindow();
|
||||
}
|
||||
|
||||
void DockDropIndicatorWindow::updateIndicatorVisibility()
|
||||
{
|
||||
for (DockDropIndicator* indicator : m_indicators)
|
||||
indicator->setVisible(m_classic_indicators->dropIndicatorVisible(indicator->location));
|
||||
}
|
||||
|
||||
void DockDropIndicatorWindow::resizeEvent(QResizeEvent* ev)
|
||||
{
|
||||
QWidget::resizeEvent(ev);
|
||||
updatePositions();
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
||||
DockDropIndicator::DockDropIndicator(KDDockWidgets::DropLocation loc, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, location(loc)
|
||||
{
|
||||
setFixedSize(INDICATOR_SIZE, INDICATOR_SIZE);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
void DockDropIndicator::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
auto [fill, outline] = pickNiceColours(palette(), hovered);
|
||||
|
||||
painter.setBrush(fill);
|
||||
|
||||
QPen pen;
|
||||
pen.setColor(outline);
|
||||
pen.setWidth(2);
|
||||
painter.setPen(pen);
|
||||
|
||||
painter.drawRect(rect());
|
||||
|
||||
QRectF rf = rect().toRectF();
|
||||
|
||||
QRectF outer = rf.marginsRemoved(QMarginsF(4.f, 4.f, 4.f, 4.f));
|
||||
QPointF icon_position;
|
||||
switch (location)
|
||||
{
|
||||
case KDDockWidgets::DropLocation_Left:
|
||||
case KDDockWidgets::DropLocation_OutterLeft:
|
||||
outer = outer.marginsRemoved(QMarginsF(0.f, 0.f, outer.width() / 2.f, 0.f));
|
||||
icon_position = rf.marginsRemoved(QMarginsF(rf.width() / 2.f, 0.f, 0.f, 0.f)).center();
|
||||
break;
|
||||
case KDDockWidgets::DropLocation_Top:
|
||||
case KDDockWidgets::DropLocation_OutterTop:
|
||||
outer = outer.marginsRemoved(QMarginsF(0.f, 0.f, 0.f, outer.width() / 2.f));
|
||||
icon_position = rf.marginsRemoved(QMarginsF(0.f, rf.width() / 2.f, 0.f, 0.f)).center();
|
||||
break;
|
||||
case KDDockWidgets::DropLocation_Right:
|
||||
case KDDockWidgets::DropLocation_OutterRight:
|
||||
outer = outer.marginsRemoved(QMarginsF(outer.width() / 2.f, 0.f, 0.f, 0.f));
|
||||
icon_position = rf.marginsRemoved(QMarginsF(0.f, 0.f, rf.width() / 2.f, 0.f)).center();
|
||||
break;
|
||||
case KDDockWidgets::DropLocation_Bottom:
|
||||
case KDDockWidgets::DropLocation_OutterBottom:
|
||||
outer = outer.marginsRemoved(QMarginsF(0.f, outer.width() / 2.f, 0.f, 0.f));
|
||||
icon_position = rf.marginsRemoved(QMarginsF(0.f, 0.f, 0.f, rf.width() / 2.f)).center();
|
||||
break;
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
painter.drawRect(outer);
|
||||
|
||||
float arrow_size = INDICATOR_SIZE / 10.f;
|
||||
|
||||
QPolygonF arrow;
|
||||
switch (location)
|
||||
{
|
||||
case KDDockWidgets::DropLocation_Left:
|
||||
arrow = {
|
||||
icon_position + QPointF(-arrow_size, 0.f),
|
||||
icon_position + QPointF(arrow_size, arrow_size * 2.f),
|
||||
icon_position + QPointF(arrow_size, -arrow_size * 2.f),
|
||||
};
|
||||
break;
|
||||
case KDDockWidgets::DropLocation_Top:
|
||||
arrow = {
|
||||
icon_position + QPointF(0.f, -arrow_size),
|
||||
icon_position + QPointF(arrow_size * 2.f, arrow_size),
|
||||
icon_position + QPointF(-arrow_size * 2.f, arrow_size),
|
||||
};
|
||||
break;
|
||||
case KDDockWidgets::DropLocation_Right:
|
||||
arrow = {
|
||||
icon_position + QPointF(arrow_size, 0.f),
|
||||
icon_position + QPointF(-arrow_size, arrow_size * 2.f),
|
||||
icon_position + QPointF(-arrow_size, -arrow_size * 2.f),
|
||||
};
|
||||
break;
|
||||
case KDDockWidgets::DropLocation_Bottom:
|
||||
arrow = {
|
||||
icon_position + QPointF(0.f, arrow_size),
|
||||
icon_position + QPointF(arrow_size * 2.f, -arrow_size),
|
||||
icon_position + QPointF(-arrow_size * 2.f, -arrow_size),
|
||||
};
|
||||
break;
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
painter.drawPolygon(arrow);
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
||||
std::string DockSegmentedDropIndicatorOverlay::s_indicator_style;
|
||||
|
||||
DockSegmentedDropIndicatorOverlay::DockSegmentedDropIndicatorOverlay(
|
||||
KDDockWidgets::Core::SegmentedDropIndicatorOverlay* controller, QWidget* parent)
|
||||
: KDDockWidgets::QtWidgets::SegmentedDropIndicatorOverlay(controller, parent)
|
||||
{
|
||||
}
|
||||
|
||||
void DockSegmentedDropIndicatorOverlay::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
if (s_indicator_style == "Minimalistic")
|
||||
drawMinimalistic();
|
||||
else
|
||||
drawSegmented();
|
||||
}
|
||||
|
||||
void DockSegmentedDropIndicatorOverlay::drawSegmented()
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
KDDockWidgets::Core::SegmentedDropIndicatorOverlay* controller =
|
||||
asController<KDDockWidgets::Core::SegmentedDropIndicatorOverlay>();
|
||||
|
||||
const std::unordered_map<KDDockWidgets::DropLocation, QPolygon>& segments = controller->segments();
|
||||
|
||||
for (KDDockWidgets::DropLocation location :
|
||||
{KDDockWidgets::DropLocation_Left,
|
||||
KDDockWidgets::DropLocation_Top,
|
||||
KDDockWidgets::DropLocation_Right,
|
||||
KDDockWidgets::DropLocation_Bottom,
|
||||
KDDockWidgets::DropLocation_Center,
|
||||
KDDockWidgets::DropLocation_OutterLeft,
|
||||
KDDockWidgets::DropLocation_OutterTop,
|
||||
KDDockWidgets::DropLocation_OutterRight,
|
||||
KDDockWidgets::DropLocation_OutterBottom})
|
||||
{
|
||||
auto segment = segments.find(location);
|
||||
if (segment == segments.end() || segment->second.size() < 2)
|
||||
continue;
|
||||
|
||||
bool hovered = segment->second.containsPoint(controller->hoveredPt(), Qt::OddEvenFill);
|
||||
auto [fill, outline] = pickNiceColours(palette(), hovered);
|
||||
|
||||
painter.setBrush(fill);
|
||||
|
||||
QPen pen(outline);
|
||||
pen.setWidth(1);
|
||||
painter.setPen(pen);
|
||||
|
||||
int margin = KDDockWidgets::Core::SegmentedDropIndicatorOverlay::s_segmentGirth * 2;
|
||||
|
||||
// Make sure the rectangles don't intersect with each other.
|
||||
QRect rect;
|
||||
switch (location)
|
||||
{
|
||||
case KDDockWidgets::DropLocation_Top:
|
||||
case KDDockWidgets::DropLocation_Bottom:
|
||||
case KDDockWidgets::DropLocation_OutterTop:
|
||||
case KDDockWidgets::DropLocation_OutterBottom:
|
||||
{
|
||||
rect = segment->second.boundingRect().marginsRemoved(QMargins(margin, 4, margin, 4));
|
||||
break;
|
||||
}
|
||||
case KDDockWidgets::DropLocation_Left:
|
||||
case KDDockWidgets::DropLocation_Right:
|
||||
case KDDockWidgets::DropLocation_OutterLeft:
|
||||
case KDDockWidgets::DropLocation_OutterRight:
|
||||
{
|
||||
rect = segment->second.boundingRect().marginsRemoved(QMargins(4, margin, 4, margin));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
rect = segment->second.boundingRect().marginsRemoved(QMargins(4, 4, 4, 4));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
painter.drawRect(rect);
|
||||
}
|
||||
}
|
||||
|
||||
void DockSegmentedDropIndicatorOverlay::drawMinimalistic()
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
KDDockWidgets::Core::SegmentedDropIndicatorOverlay* controller =
|
||||
asController<KDDockWidgets::Core::SegmentedDropIndicatorOverlay>();
|
||||
|
||||
const std::unordered_map<KDDockWidgets::DropLocation, QPolygon>& segments = controller->segments();
|
||||
|
||||
for (KDDockWidgets::DropLocation location :
|
||||
{KDDockWidgets::DropLocation_Left,
|
||||
KDDockWidgets::DropLocation_Top,
|
||||
KDDockWidgets::DropLocation_Right,
|
||||
KDDockWidgets::DropLocation_Bottom,
|
||||
KDDockWidgets::DropLocation_Center,
|
||||
KDDockWidgets::DropLocation_OutterLeft,
|
||||
KDDockWidgets::DropLocation_OutterTop,
|
||||
KDDockWidgets::DropLocation_OutterRight,
|
||||
KDDockWidgets::DropLocation_OutterBottom})
|
||||
{
|
||||
auto segment = segments.find(location);
|
||||
if (segment == segments.end() || segment->second.size() < 2)
|
||||
continue;
|
||||
|
||||
if (!segment->second.containsPoint(controller->hoveredPt(), Qt::OddEvenFill))
|
||||
continue;
|
||||
|
||||
auto [fill, outline] = pickNiceColours(palette(), true);
|
||||
|
||||
painter.setBrush(fill);
|
||||
|
||||
QPen pen(outline);
|
||||
pen.setWidth(1);
|
||||
painter.setPen(pen);
|
||||
|
||||
painter.drawRect(segment->second.boundingRect());
|
||||
}
|
||||
}
|
||||
108
pcsx2-qt/Debugger/Docking/DropIndicators.h
Normal file
108
pcsx2-qt/Debugger/Docking/DropIndicators.h
Normal file
@@ -0,0 +1,108 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kddockwidgets/core/indicators/ClassicDropIndicatorOverlay.h>
|
||||
#include <kddockwidgets/core/views/ClassicIndicatorWindowViewInterface.h>
|
||||
#include <kddockwidgets/qtwidgets/views/SegmentedDropIndicatorOverlay.h>
|
||||
|
||||
class DockDropIndicator;
|
||||
|
||||
// This switches between our custom drop indicators and KDDockWidget's built-in
|
||||
// ones on the fly depending on whether or not we have a windowing system that
|
||||
// supports compositing.
|
||||
class DockDropIndicatorProxy : public KDDockWidgets::Core::ClassicIndicatorWindowViewInterface
|
||||
{
|
||||
public:
|
||||
DockDropIndicatorProxy(KDDockWidgets::Core::ClassicDropIndicatorOverlay* classic_indicators);
|
||||
~DockDropIndicatorProxy();
|
||||
|
||||
void setObjectName(const QString&) override;
|
||||
KDDockWidgets::DropLocation hover(QPoint globalPos) override;
|
||||
QPoint posForIndicator(KDDockWidgets::DropLocation) const override;
|
||||
void updatePositions() override;
|
||||
void raise() override;
|
||||
void setVisible(bool visible) override;
|
||||
void resize(QSize size) override;
|
||||
void setGeometry(QRect rect) override;
|
||||
bool isWindow() const override;
|
||||
void updateIndicatorVisibility() override;
|
||||
|
||||
private:
|
||||
KDDockWidgets::Core::ClassicIndicatorWindowViewInterface* window();
|
||||
const KDDockWidgets::Core::ClassicIndicatorWindowViewInterface* window() const;
|
||||
|
||||
void recreateWindowIfNecessary();
|
||||
|
||||
KDDockWidgets::Core::ClassicIndicatorWindowViewInterface* m_window = nullptr;
|
||||
KDDockWidgets::Core::ClassicIndicatorWindowViewInterface* m_fallback_window = nullptr;
|
||||
|
||||
bool m_supports_compositing = true;
|
||||
KDDockWidgets::Core::ClassicDropIndicatorOverlay* m_classic_indicators = nullptr;
|
||||
};
|
||||
|
||||
// Our default custom drop indicator implementation. This fits in with PCSX2's
|
||||
// themes a lot better, but doesn't support windowing systems where compositing
|
||||
// is disabled (it would show a black screen).
|
||||
class DockDropIndicatorWindow : public QWidget, public KDDockWidgets::Core::ClassicIndicatorWindowViewInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DockDropIndicatorWindow(
|
||||
KDDockWidgets::Core::ClassicDropIndicatorOverlay* classic_indicators);
|
||||
|
||||
void setObjectName(const QString& name) override;
|
||||
KDDockWidgets::DropLocation hover(QPoint globalPos) override;
|
||||
QPoint posForIndicator(KDDockWidgets::DropLocation loc) const override;
|
||||
void updatePositions() override;
|
||||
void raise() override;
|
||||
void setVisible(bool visible) override;
|
||||
void resize(QSize size) override;
|
||||
void setGeometry(QRect rect) override;
|
||||
bool isWindow() const override;
|
||||
void updateIndicatorVisibility() override;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* ev) override;
|
||||
|
||||
private:
|
||||
KDDockWidgets::Core::ClassicDropIndicatorOverlay* m_classic_indicators;
|
||||
std::vector<DockDropIndicator*> m_indicators;
|
||||
};
|
||||
|
||||
class DockDropIndicator : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DockDropIndicator(KDDockWidgets::DropLocation loc, QWidget* parent = nullptr);
|
||||
|
||||
KDDockWidgets::DropLocation location;
|
||||
bool hovered = false;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
};
|
||||
|
||||
// An alternative drop indicator design that can be enabled from the settings
|
||||
// menu. For this one we don't need to worry about whether compositing is
|
||||
// supported since it doesn't create its own window.
|
||||
class DockSegmentedDropIndicatorOverlay : public KDDockWidgets::QtWidgets::SegmentedDropIndicatorOverlay
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DockSegmentedDropIndicatorOverlay(
|
||||
KDDockWidgets::Core::SegmentedDropIndicatorOverlay* controller, QWidget* parent = nullptr);
|
||||
|
||||
static std::string s_indicator_style;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
private:
|
||||
void drawSegmented();
|
||||
void drawMinimalistic();
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user