mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
156 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ad825d1e0 | ||
|
|
7910506b3c | ||
|
|
5393d724c5 | ||
|
|
c8b1e4c4e6 | ||
|
|
d373cb602d | ||
|
|
58f195fc04 | ||
|
|
f6675808fc | ||
|
|
aa64712354 | ||
|
|
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 |
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."
|
||||
|
||||
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.12
|
||||
SDL=SDL3-3.2.8
|
||||
QT=6.8.2
|
||||
ZSTD=1.5.6
|
||||
ZSTD=1.5.7
|
||||
KDDOCKWIDGETS=2.2.1
|
||||
|
||||
SHADERC=2024.1
|
||||
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -33,12 +34,12 @@ 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
|
||||
ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea $SDL.tar.gz
|
||||
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
|
||||
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
|
||||
@@ -49,11 +50,12 @@ eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADE
|
||||
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.12.tar.gz",
|
||||
"sha256": "ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea"
|
||||
"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.12
|
||||
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
|
||||
ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea $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.12
|
||||
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
|
||||
ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea $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.2
|
||||
set QTMINOR=6.8
|
||||
set SDL=SDL2-2.30.12
|
||||
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" aa2808d0f2dc6b383c6689bf6d166e2de62db4d58be989e4b052acb31df0fba3 || 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.2
|
||||
set QTMINOR=6.8
|
||||
set SDL=SDL2-2.30.12
|
||||
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" aa2808d0f2dc6b383c6689bf6d166e2de62db4d58be989e4b052acb31df0fba3 || 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");
|
||||
|
||||
3
3rdparty/imgui/include/imconfig.h
vendored
3
3rdparty/imgui/include/imconfig.h
vendored
@@ -88,8 +88,7 @@
|
||||
|
||||
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
|
||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||
// - lunasvg is currently easier to acquire/install, as e.g. it is part of vcpkg.
|
||||
// - plutosvg will support more fonts and may load them faster. It currently requires to be built manually but it is fairly easy. See misc/freetype/README for instructions.
|
||||
// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions.
|
||||
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
|
||||
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
||||
|
||||
119
3rdparty/imgui/include/imgui.h
vendored
119
3rdparty/imgui/include/imgui.h
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.8
|
||||
// dear imgui, v1.91.9b
|
||||
// (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.8"
|
||||
#define IMGUI_VERSION_NUM 19180
|
||||
#define IMGUI_VERSION "1.91.9b"
|
||||
#define IMGUI_VERSION_NUM 19191
|
||||
#define IMGUI_HAS_TABLE
|
||||
|
||||
/*
|
||||
@@ -37,6 +37,7 @@
|
||||
Index of this file:
|
||||
// [SECTION] Header mess
|
||||
// [SECTION] Forward declarations and basic types
|
||||
// [SECTION] Texture identifier (ImTextureID)
|
||||
// [SECTION] Dear ImGui end-user API functions
|
||||
// [SECTION] Flags & Enumerations
|
||||
// [SECTION] Tables API flags and structures (ImGuiTableFlags, ImGuiTableColumnFlags, ImGuiTableRowFlags, ImGuiTableBgTarget, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs)
|
||||
@@ -250,22 +251,6 @@ typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: f
|
||||
typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport
|
||||
typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild()
|
||||
|
||||
// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type]
|
||||
// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file.
|
||||
// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details.
|
||||
// - You can make this a structure with various constructors if you need. You will have to implement ==/!= operators.
|
||||
// - (note: before v1.91.4 (2024/10/08) the default type for ImTextureID was void*. Use intermediary intptr_t cast and read FAQ if you have casting warnings)
|
||||
#ifndef ImTextureID
|
||||
typedef ImU64 ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that)
|
||||
#endif
|
||||
|
||||
// ImDrawIdx: vertex index. [Compile-time configurable type]
|
||||
// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended).
|
||||
// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file.
|
||||
#ifndef ImDrawIdx
|
||||
typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends)
|
||||
#endif
|
||||
|
||||
// Character types
|
||||
// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display)
|
||||
typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings.
|
||||
@@ -315,6 +300,19 @@ struct ImVec4
|
||||
};
|
||||
IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Texture identifier (ImTextureID)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type]
|
||||
// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file.
|
||||
// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details.
|
||||
// - You can make this a structure with various constructors if you need. You will have to implement ==/!= operators.
|
||||
// - (note: before v1.91.4 (2024/10/08) the default type for ImTextureID was void*. Use intermediary intptr_t cast and read FAQ if you have casting warnings)
|
||||
#ifndef ImTextureID
|
||||
typedef ImU64 ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that)
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Dear ImGui end-user API functions
|
||||
// (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!)
|
||||
@@ -544,7 +542,7 @@ namespace ImGui
|
||||
IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2);
|
||||
IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text()
|
||||
IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1);
|
||||
IMGUI_API void SeparatorText(const char* label); // currently: formatted text with an horizontal line
|
||||
IMGUI_API void SeparatorText(const char* label); // currently: formatted text with a horizontal line
|
||||
|
||||
// Widgets: Main
|
||||
// - Most widgets return true when the value has been changed or when pressed/selected
|
||||
@@ -566,9 +564,10 @@ namespace ImGui
|
||||
// Widgets: Images
|
||||
// - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
|
||||
// - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above.
|
||||
// - Note that Image() may add +2.0f to provided size if a border is visible, ImageButton() adds style.FramePadding*2.0f to provided size.
|
||||
// - Image() pads adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side.
|
||||
// - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified.
|
||||
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& border_col = ImVec4(0, 0, 0, 0));
|
||||
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1));
|
||||
IMGUI_API void ImageWithBg(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1));
|
||||
IMGUI_API bool ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1));
|
||||
|
||||
// Widgets: Combo Box (Dropdown)
|
||||
@@ -906,7 +905,7 @@ namespace ImGui
|
||||
IMGUI_API void PopClipRect();
|
||||
|
||||
// Focus, Activation
|
||||
IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of of a newly appearing window.
|
||||
IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a newly appearing window.
|
||||
IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget.
|
||||
|
||||
// Keyboard/Gamepad Navigation
|
||||
@@ -974,7 +973,7 @@ namespace ImGui
|
||||
IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)?
|
||||
IMGUI_API bool IsKeyChordPressed(ImGuiKeyChord key_chord); // was key chord (mods + key) pressed, e.g. you can pass 'ImGuiMod_Ctrl | ImGuiKey_S' as a key-chord. This doesn't do any routing or focus check, please consider using Shortcut() function instead.
|
||||
IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate
|
||||
IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names a provided for debugging purpose and are not meant to be saved persistently not compared.
|
||||
IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names are provided for debugging purpose and are not meant to be saved persistently nor compared.
|
||||
IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard); // Override io.WantCaptureKeyboard flag next frame (said flag is left for your application to handle, typically when true it instructs your app to ignore inputs). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard"; after the next NewFrame() call.
|
||||
|
||||
// Inputs Utilities: Shortcut Testing & Routing [BETA]
|
||||
@@ -1177,7 +1176,7 @@ enum ImGuiInputTextFlags_
|
||||
ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID().
|
||||
|
||||
// Elide display / Alignment
|
||||
ImGuiInputTextFlags_ElideLeft = 1 << 17, // When text doesn't fit, elide left side to ensure right side stays visible. Useful for path/filenames. Single-line only!
|
||||
ImGuiInputTextFlags_ElideLeft = 1 << 17, // When text doesn't fit, elide left side to ensure right side stays visible. Useful for path/filenames. Single-line only!
|
||||
|
||||
// Callback features
|
||||
ImGuiInputTextFlags_CallbackCompletion = 1 << 18, // Callback on pressing TAB (for completion handling)
|
||||
@@ -1492,6 +1491,7 @@ enum ImGuiKey : int
|
||||
ImGuiKey_KeypadEqual,
|
||||
ImGuiKey_AppBack, // Available on some keyboard/mouses. Often referred as "Browser Back"
|
||||
ImGuiKey_AppForward,
|
||||
ImGuiKey_Oem102, // Non-US backslash.
|
||||
|
||||
// Gamepad (some of those are analog values, 0.0f to 1.0f) // NAVIGATION ACTION
|
||||
// (download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets)
|
||||
@@ -1714,6 +1714,7 @@ enum ImGuiStyleVar_
|
||||
ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding
|
||||
ImGuiStyleVar_GrabMinSize, // float GrabMinSize
|
||||
ImGuiStyleVar_GrabRounding, // float GrabRounding
|
||||
ImGuiStyleVar_ImageBorderSize, // float ImageBorderSize
|
||||
ImGuiStyleVar_TabRounding, // float TabRounding
|
||||
ImGuiStyleVar_TabBorderSize, // float TabBorderSize
|
||||
ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize
|
||||
@@ -1833,6 +1834,8 @@ enum ImGuiMouseCursor_
|
||||
ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window
|
||||
ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window
|
||||
ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks)
|
||||
ImGuiMouseCursor_Wait, // When waiting for something to process/load.
|
||||
ImGuiMouseCursor_Progress, // When waiting for something to process/load, but application is still interactive.
|
||||
ImGuiMouseCursor_NotAllowed, // When hovering something with disallowed interaction. Usually a crossed circle.
|
||||
ImGuiMouseCursor_COUNT
|
||||
};
|
||||
@@ -2146,6 +2149,7 @@ struct ImGuiStyle
|
||||
ImVec2 WindowPadding; // Padding within a window.
|
||||
float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
|
||||
float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
|
||||
float WindowBorderHoverPadding; // Hit-testing extent outside/inside resizing border. Also extend determination of hovered window. Generally meaningfully larger than WindowBorderSize to make it easy to reach borders.
|
||||
ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constrain individual windows, use SetNextWindowSizeConstraints().
|
||||
ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered.
|
||||
ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left.
|
||||
@@ -2167,9 +2171,11 @@ struct ImGuiStyle
|
||||
float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar.
|
||||
float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
|
||||
float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
|
||||
float ImageBorderSize; // Thickness of border around Image() calls.
|
||||
float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
|
||||
float TabBorderSize; // Thickness of border around tabs.
|
||||
float TabMinWidthForCloseButton; // 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.
|
||||
float TabCloseButtonMinWidthSelected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width.
|
||||
float TabCloseButtonMinWidthUnselected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected.
|
||||
float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
|
||||
float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar.
|
||||
float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees).
|
||||
@@ -2188,6 +2194,8 @@ struct ImGuiStyle
|
||||
bool AntiAliasedFill; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList).
|
||||
float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
|
||||
float CircleTessellationMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
|
||||
|
||||
// Colors
|
||||
ImVec4 Colors[ImGuiCol_COUNT];
|
||||
|
||||
// Behaviors
|
||||
@@ -2200,6 +2208,11 @@ struct ImGuiStyle
|
||||
|
||||
IMGUI_API ImGuiStyle();
|
||||
IMGUI_API void ScaleAllSizes(float scale_factor);
|
||||
|
||||
// Obsolete names
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
// TabMinWidthForCloseButton = TabCloseButtonMinWidthUnselected // Renamed in 1.91.9.
|
||||
#endif
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -2310,7 +2323,8 @@ struct ImGuiIO
|
||||
// - Code should use PushID()/PopID() in loops, or append "##xx" to same-label identifiers.
|
||||
// - Empty label e.g. Button("") == same ID as parent widget/node. Use Button("##xx") instead!
|
||||
// - See FAQ https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system
|
||||
bool ConfigDebugHighlightIdConflicts;// = true // Highlight and show an error message when multiple items have conflicting identifiers.
|
||||
bool ConfigDebugHighlightIdConflicts;// = true // Highlight and show an error message popup when multiple items have conflicting identifiers.
|
||||
bool ConfigDebugHighlightIdConflictsShowItemPicker;//=true // Show "Item Picker" button in aforementioned popup.
|
||||
|
||||
// Tools to test correct Begin/End and BeginChild/EndChild behaviors.
|
||||
// - Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX()
|
||||
@@ -2420,7 +2434,7 @@ struct ImGuiIO
|
||||
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.
|
||||
bool MouseCtrlLeftAsRightClick; // (OSX) Set to true when the current click was a ctrl-click that spawned a simulated right click
|
||||
bool MouseCtrlLeftAsRightClick; // (OSX) Set to true when the current click was a Ctrl+click that spawned a simulated right click
|
||||
float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked)
|
||||
float MouseDownDurationPrev[5]; // Previous time the mouse button has been down
|
||||
float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds)
|
||||
@@ -2585,10 +2599,11 @@ struct ImGuiTextBuffer
|
||||
ImGuiTextBuffer() { }
|
||||
inline char operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; }
|
||||
const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; }
|
||||
const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator
|
||||
const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator
|
||||
int size() const { return Buf.Size ? Buf.Size - 1 : 0; }
|
||||
bool empty() const { return Buf.Size <= 1; }
|
||||
void clear() { Buf.clear(); }
|
||||
void resize(int size) { if (Buf.Size > size) Buf.Data[size] = 0; Buf.resize(size ? size + 1 : 0, 0); } // Similar to resize(0) on ImVector: empty string but don't free buffer.
|
||||
void reserve(int capacity) { Buf.reserve(capacity); }
|
||||
const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; }
|
||||
IMGUI_API void append(const char* str, const char* str_end = NULL);
|
||||
@@ -2940,6 +2955,13 @@ struct ImGuiSelectionExternalStorage
|
||||
#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (32)
|
||||
#endif
|
||||
|
||||
// ImDrawIdx: vertex index. [Compile-time configurable type]
|
||||
// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended).
|
||||
// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file.
|
||||
#ifndef ImDrawIdx
|
||||
typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends)
|
||||
#endif
|
||||
|
||||
// ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h]
|
||||
// NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering,
|
||||
// you can poke into the draw list for that! Draw callback may be useful for example to:
|
||||
@@ -3131,7 +3153,7 @@ struct ImDrawList
|
||||
|
||||
// General polygon
|
||||
// - Only simple polygons are supported by filling functions (no self-intersections, no holes).
|
||||
// - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience fo user but not used by main library.
|
||||
// - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience for the user but not used by the main library.
|
||||
IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness);
|
||||
IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col);
|
||||
IMGUI_API void AddConcavePolyFilled(const ImVec2* points, int num_points, ImU32 col);
|
||||
@@ -3257,11 +3279,12 @@ struct ImFontConfig
|
||||
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 GlyphExtraSpacing; // 0, 0 // (REMOVED IN 1.91.9: use GlyphExtraAdvanceX)
|
||||
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
|
||||
float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this.
|
||||
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.
|
||||
@@ -3281,7 +3304,7 @@ struct ImFontGlyph
|
||||
unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops)
|
||||
unsigned int Visible : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering.
|
||||
unsigned int Codepoint : 30; // 0x0000..0x10FFFF
|
||||
float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in)
|
||||
float AdvanceX; // Horizontal distance to advance layout with
|
||||
float X0, Y0, X1, Y1; // Glyph corners
|
||||
float U0, V0, U1, V1; // Texture coordinates
|
||||
};
|
||||
@@ -3405,12 +3428,12 @@ struct ImFontAtlas
|
||||
|
||||
// [Internal]
|
||||
IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const;
|
||||
IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]);
|
||||
|
||||
//-------------------------------------------
|
||||
// Members
|
||||
//-------------------------------------------
|
||||
|
||||
// Input
|
||||
ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_)
|
||||
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.
|
||||
@@ -3430,7 +3453,7 @@ struct ImFontAtlas
|
||||
ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel
|
||||
ImVector<ImFont*> Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font.
|
||||
ImVector<ImFontAtlasCustomRect> CustomRects; // Rectangles for packing custom texture data into the atlas.
|
||||
ImVector<ImFontConfig> ConfigData; // Configuration data
|
||||
ImVector<ImFontConfig> Sources; // Source/configuration data
|
||||
ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines
|
||||
|
||||
// [Internal] Font builder
|
||||
@@ -3442,8 +3465,8 @@ struct ImFontAtlas
|
||||
int PackIdLines; // Custom texture rectangle ID for baked anti-aliased lines
|
||||
|
||||
// [Obsolete]
|
||||
//typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+
|
||||
//typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+
|
||||
//typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+
|
||||
//typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+
|
||||
};
|
||||
|
||||
// Font runtime data and rendering
|
||||
@@ -3458,13 +3481,13 @@ struct ImFont
|
||||
// [Internal] Members: Hot ~28/40 bytes (for RenderText loop)
|
||||
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)
|
||||
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.
|
||||
// Conceptually Sources[] 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 // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont.
|
||||
ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances
|
||||
short SourcesCount; // 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 // Character used if a glyph isn't found (U+FFFD, '?')
|
||||
@@ -3479,12 +3502,13 @@ struct ImFont
|
||||
// Methods
|
||||
IMGUI_API ImFont();
|
||||
IMGUI_API ~ImFont();
|
||||
IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c);
|
||||
IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c);
|
||||
IMGUI_API ImFontGlyph* FindGlyph(ImWchar c);
|
||||
IMGUI_API 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>"; }
|
||||
const char* GetDebugName() const { return Sources ? Sources->Name : "<unknown>"; }
|
||||
|
||||
// [Internal] Don't use!
|
||||
// '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.
|
||||
IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL); // utf8
|
||||
@@ -3498,7 +3522,6 @@ struct ImFont
|
||||
IMGUI_API void GrowIndex(int new_size);
|
||||
IMGUI_API void AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x);
|
||||
IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built.
|
||||
IMGUI_API void SetGlyphVisible(ImWchar c, bool visible);
|
||||
IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last);
|
||||
};
|
||||
|
||||
@@ -3552,7 +3575,7 @@ struct ImGuiPlatformIO
|
||||
IMGUI_API ImGuiPlatformIO();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Interface with OS and Platform backend
|
||||
// Input - Interface with OS and Platform backend (most common stuff)
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// Optional: Access OS clipboard
|
||||
@@ -3562,7 +3585,7 @@ struct ImGuiPlatformIO
|
||||
void* Platform_ClipboardUserData;
|
||||
|
||||
// Optional: Open link/folder/file in OS Shell
|
||||
// (default to use ShellExecuteA() on Windows, system() on Linux/Mac)
|
||||
// (default to use ShellExecuteW() on Windows, system() on Linux/Mac)
|
||||
bool (*Platform_OpenInShellFn)(ImGuiContext* ctx, const char* path);
|
||||
void* Platform_OpenInShellUserData;
|
||||
|
||||
@@ -3577,7 +3600,7 @@ struct ImGuiPlatformIO
|
||||
ImWchar Platform_LocaleDecimalPoint; // '.'
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Interface with Renderer Backend
|
||||
// Input - Interface with Renderer Backend
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure.
|
||||
@@ -3603,6 +3626,8 @@ struct ImGuiPlatformImeData
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
namespace ImGui
|
||||
{
|
||||
// OBSOLETED in 1.91.9 (from February 2025)
|
||||
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- border_col was removed in favor of ImGuiCol_ImageBorder.
|
||||
// OBSOLETED in 1.91.0 (from July 2024)
|
||||
static inline void PushButtonRepeat(bool repeat) { PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); }
|
||||
static inline void PopButtonRepeat() { PopItemFlag(); }
|
||||
|
||||
116
3rdparty/imgui/include/imgui_internal.h
vendored
116
3rdparty/imgui/include/imgui_internal.h
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.8
|
||||
// dear imgui, v1.91.9b
|
||||
// (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.
|
||||
@@ -14,6 +14,7 @@ Index of this file:
|
||||
// [SECTION] Macros
|
||||
// [SECTION] Generic helpers
|
||||
// [SECTION] ImDrawList support
|
||||
// [SECTION] Style support
|
||||
// [SECTION] Data types support
|
||||
// [SECTION] Widgets support: flags, enums, data structures
|
||||
// [SECTION] Popup support
|
||||
@@ -145,7 +146,6 @@ struct ImGuiBoxSelectState; // Box-selection state (currently used by mu
|
||||
struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it
|
||||
struct ImGuiContext; // Main Dear ImGui context
|
||||
struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine
|
||||
struct ImGuiDataVarInfo; // Variable information (e.g. to access style variables from an enum)
|
||||
struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum
|
||||
struct ImGuiDeactivatedItemData; // Data for IsItemDeactivated()/IsItemDeactivatedAfterEdit() function.
|
||||
struct ImGuiErrorRecoveryState; // Storage of stack sizes for error handling and recovery
|
||||
@@ -166,6 +166,7 @@ struct ImGuiOldColumns; // Storage data for a columns set for legacy
|
||||
struct ImGuiPopupData; // Storage for current popup stack
|
||||
struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file
|
||||
struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it
|
||||
struct ImGuiStyleVarInfo; // Style variable information (e.g. to access style variables from an enum)
|
||||
struct ImGuiTabBar; // Storage for a tab bar
|
||||
struct ImGuiTabItem; // Storage for a tab item (within a tab bar)
|
||||
struct ImGuiTable; // Storage for a table
|
||||
@@ -366,11 +367,14 @@ static inline void ImQsort(void* base, size_t count, size_t size_of_element
|
||||
IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b);
|
||||
|
||||
// Helpers: Bit manipulation
|
||||
static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
|
||||
static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; }
|
||||
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
|
||||
static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
|
||||
static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; }
|
||||
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
|
||||
static inline unsigned int ImCountSetBits(unsigned int v) { unsigned int count = 0; while (v > 0) { v = v & (v - 1); count++; } return count; }
|
||||
|
||||
// Helpers: String
|
||||
#define ImStrlen strlen
|
||||
#define ImMemchr memchr
|
||||
IMGUI_API int ImStricmp(const char* str1, const char* str2); // Case insensitive compare.
|
||||
IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); // Case insensitive compare to a certain count.
|
||||
IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); // Copy to a certain count and always zero terminate (strncpy doesn't).
|
||||
@@ -786,8 +790,9 @@ struct IMGUI_API ImDrawListSharedData
|
||||
float FontScale; // Current/default font scale (== FontSize / Font->FontSize)
|
||||
float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo()
|
||||
float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc
|
||||
ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen()
|
||||
float InitialFringeScale; // Initial scale to apply to AA fringe
|
||||
ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards)
|
||||
ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen()
|
||||
ImVector<ImVec2> TempBuffer; // Temporary write buffer
|
||||
|
||||
// Lookup tables
|
||||
@@ -808,17 +813,38 @@ struct ImDrawDataBuilder
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Data types support
|
||||
// [SECTION] Style support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiDataVarInfo
|
||||
struct ImGuiStyleVarInfo
|
||||
{
|
||||
ImGuiDataType Type;
|
||||
ImU32 Count; // 1+
|
||||
ImU32 Offset; // Offset in parent structure
|
||||
ImU32 Count : 8; // 1+
|
||||
ImGuiDataType DataType : 8;
|
||||
ImU32 Offset : 16; // Offset in parent structure
|
||||
void* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); }
|
||||
};
|
||||
|
||||
// Stacked color modifier, backup of modified data so we can restore it
|
||||
struct ImGuiColorMod
|
||||
{
|
||||
ImGuiCol Col;
|
||||
ImVec4 BackupValue;
|
||||
};
|
||||
|
||||
// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable.
|
||||
struct ImGuiStyleMod
|
||||
{
|
||||
ImGuiStyleVar VarIdx;
|
||||
union { int BackupInt[2]; float BackupFloat[2]; };
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; }
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; }
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Data types support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiDataTypeStorage
|
||||
{
|
||||
ImU8 Data[8]; // Opaque storage to fit any data up to ImGuiDataType_COUNT
|
||||
@@ -836,7 +862,7 @@ struct ImGuiDataTypeInfo
|
||||
// Extend ImGuiDataType_
|
||||
enum ImGuiDataTypePrivate_
|
||||
{
|
||||
ImGuiDataType_Pointer = ImGuiDataType_COUNT + 1,
|
||||
ImGuiDataType_Pointer = ImGuiDataType_COUNT,
|
||||
ImGuiDataType_ID,
|
||||
};
|
||||
|
||||
@@ -1037,23 +1063,6 @@ enum ImGuiPlotType
|
||||
ImGuiPlotType_Histogram,
|
||||
};
|
||||
|
||||
// Stacked color modifier, backup of modified data so we can restore it
|
||||
struct ImGuiColorMod
|
||||
{
|
||||
ImGuiCol Col;
|
||||
ImVec4 BackupValue;
|
||||
};
|
||||
|
||||
// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable.
|
||||
struct ImGuiStyleMod
|
||||
{
|
||||
ImGuiStyleVar VarIdx;
|
||||
union { int BackupInt[2]; float BackupFloat[2]; };
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; }
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; }
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; }
|
||||
};
|
||||
|
||||
// Storage data for BeginComboPreview()/EndComboPreview()
|
||||
struct IMGUI_API ImGuiComboPreviewData
|
||||
{
|
||||
@@ -1194,14 +1203,17 @@ enum ImGuiNextWindowDataFlags_
|
||||
ImGuiNextWindowDataFlags_HasFocus = 1 << 5,
|
||||
ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6,
|
||||
ImGuiNextWindowDataFlags_HasScroll = 1 << 7,
|
||||
ImGuiNextWindowDataFlags_HasChildFlags = 1 << 8,
|
||||
ImGuiNextWindowDataFlags_HasRefreshPolicy = 1 << 9,
|
||||
ImGuiNextWindowDataFlags_HasWindowFlags = 1 << 8,
|
||||
ImGuiNextWindowDataFlags_HasChildFlags = 1 << 9,
|
||||
ImGuiNextWindowDataFlags_HasRefreshPolicy = 1 << 10,
|
||||
};
|
||||
|
||||
// Storage for SetNexWindow** functions
|
||||
struct ImGuiNextWindowData
|
||||
{
|
||||
ImGuiNextWindowDataFlags Flags;
|
||||
ImGuiNextWindowDataFlags HasFlags;
|
||||
|
||||
// Members below are NOT cleared. Always rely on HasFlags.
|
||||
ImGuiCond PosCond;
|
||||
ImGuiCond SizeCond;
|
||||
ImGuiCond CollapsedCond;
|
||||
@@ -1210,6 +1222,7 @@ struct ImGuiNextWindowData
|
||||
ImVec2 SizeVal;
|
||||
ImVec2 ContentSizeVal;
|
||||
ImVec2 ScrollVal;
|
||||
ImGuiWindowFlags WindowFlags; // Only honored by BeginTable()
|
||||
ImGuiChildFlags ChildFlags;
|
||||
bool CollapsedVal;
|
||||
ImRect SizeConstraintRect;
|
||||
@@ -1220,7 +1233,7 @@ struct ImGuiNextWindowData
|
||||
ImGuiWindowRefreshFlags RefreshFlagsVal;
|
||||
|
||||
ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); }
|
||||
inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }
|
||||
inline void ClearFlags() { HasFlags = ImGuiNextWindowDataFlags_None; }
|
||||
};
|
||||
|
||||
enum ImGuiNextItemDataFlags_
|
||||
@@ -1237,7 +1250,8 @@ struct ImGuiNextItemData
|
||||
{
|
||||
ImGuiNextItemDataFlags HasFlags; // Called HasFlags instead of Flags to avoid mistaking this
|
||||
ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap and ImGuiItemFlags_HasSelectionUserData.
|
||||
// Non-flags members are NOT cleared by ItemAdd() meaning they are still valid during NavProcessItem()
|
||||
|
||||
// Members below are NOT cleared by ItemAdd() meaning they are still valid during e.g. NavProcessItem(). Always rely on HasFlags.
|
||||
ImGuiID FocusScopeId; // Set by SetNextItemSelectionUserData()
|
||||
ImGuiSelectionUserData SelectionUserData; // Set by SetNextItemSelectionUserData() (note that NULL/0 is a valid value, we use -1 == ImGuiSelectionUserData_Invalid to mark invalid values)
|
||||
float Width; // Set by SetNextItemWidth()
|
||||
@@ -1305,6 +1319,7 @@ struct ImGuiWindowStackData
|
||||
ImGuiLastItemData ParentLastItemDataBackup;
|
||||
ImGuiErrorRecoveryState StackSizesInBegin; // Store size of various stacks for asserting
|
||||
bool DisabledOverrideReenable; // Non-child window override disabled flag
|
||||
float DisabledOverrideReenableAlphaBackup;
|
||||
};
|
||||
|
||||
struct ImGuiShrinkWidthItem
|
||||
@@ -1992,7 +2007,6 @@ struct ImGuiMetricsConfig
|
||||
bool ShowDrawCmdMesh = true;
|
||||
bool ShowDrawCmdBoundingBoxes = true;
|
||||
bool ShowTextEncodingViewer = false;
|
||||
bool ShowAtlasTintedWithTextColor = false;
|
||||
int ShowWindowsRectsType = -1;
|
||||
int ShowTablesRectsType = -1;
|
||||
int HighlightMonitorIdx = -1;
|
||||
@@ -2019,6 +2033,7 @@ struct ImGuiIDStackTool
|
||||
ImVector<ImGuiStackLevelInfo> Results;
|
||||
bool CopyToClipboardOnCtrlC;
|
||||
float CopyToClipboardLastTime;
|
||||
ImGuiTextBuffer ResultPathBuf;
|
||||
|
||||
ImGuiIDStackTool() { memset(this, 0, sizeof(*this)); CopyToClipboardLastTime = -FLT_MAX; }
|
||||
};
|
||||
@@ -2083,7 +2098,7 @@ struct ImGuiContext
|
||||
ImVector<ImGuiWindowStackData> CurrentWindowStack;
|
||||
ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow*
|
||||
int WindowsActiveCount; // Number of unique windows submitted by frame
|
||||
ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING).
|
||||
float WindowsBorderHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, style.WindowBorderHoverPadding). This isn't so multi-dpi friendly.
|
||||
ImGuiID DebugBreakInWindow; // Set to break in Begin() call.
|
||||
ImGuiWindow* CurrentWindow; // Window being drawn into
|
||||
ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs.
|
||||
@@ -2500,6 +2515,8 @@ struct IMGUI_API ImGuiWindow
|
||||
ImVec2 ScrollTargetEdgeSnapDist; // 0.0f = no snapping, >0.0f snapping threshold
|
||||
ImVec2 ScrollbarSizes; // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar.
|
||||
bool ScrollbarX, ScrollbarY; // Are scrollbars visible?
|
||||
bool ScrollbarXStabilizeEnabled; // Was ScrollbarX previously auto-stabilized?
|
||||
ImU8 ScrollbarXStabilizeToggledHistory; // Used to stabilize scrollbar visibility in case of feedback loops
|
||||
bool Active; // Set to true on Begin(), unless Collapsed
|
||||
bool WasActive;
|
||||
bool WriteAccessed; // Set to true when any widget access the current window
|
||||
@@ -2787,7 +2804,7 @@ struct IMGUI_API ImGuiTable
|
||||
{
|
||||
ImGuiID ID;
|
||||
ImGuiTableFlags Flags;
|
||||
void* RawData; // Single allocation to hold Columns[], DisplayOrderToIndex[] and RowCellData[]
|
||||
void* RawData; // Single allocation to hold Columns[], DisplayOrderToIndex[], and RowCellData[]
|
||||
ImGuiTableTempData* TempData; // Transient data while table is active. Point within g.CurrentTableStack[]
|
||||
ImSpan<ImGuiTableColumn> Columns; // Point within RawData[]
|
||||
ImSpan<ImGuiTableColumnIdx> DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1)
|
||||
@@ -2801,7 +2818,7 @@ struct IMGUI_API ImGuiTable
|
||||
int ColumnsCount; // Number of columns declared in BeginTable()
|
||||
int CurrentRow;
|
||||
int CurrentColumn;
|
||||
ImS16 InstanceCurrent; // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple table with same ID look are multiple tables, they are just synched.
|
||||
ImS16 InstanceCurrent; // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple tables with the same ID are multiple tables, they are just synced.
|
||||
ImS16 InstanceInteracted; // Mark which instance (generally 0) of the same ID is being interacted with
|
||||
float RowPosY1;
|
||||
float RowPosY2;
|
||||
@@ -2833,7 +2850,7 @@ struct IMGUI_API ImGuiTable
|
||||
float AngledHeadersHeight; // Set by TableAngledHeadersRow(), used in TableUpdateLayout()
|
||||
float AngledHeadersSlope; // Set by TableAngledHeadersRow(), used in TableUpdateLayout()
|
||||
ImRect OuterRect; // Note: for non-scrolling table, OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable().
|
||||
ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is
|
||||
ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is "
|
||||
ImRect WorkRect;
|
||||
ImRect InnerClipRect;
|
||||
ImRect BgClipRect; // We use this to cpu-clip cell background color fill, evolve during the frame as we cross frozen rows boundaries
|
||||
@@ -2930,7 +2947,7 @@ struct IMGUI_API ImGuiTableTempData
|
||||
ImGuiTableTempData() { memset(this, 0, sizeof(*this)); LastTimeActive = -1.0f; }
|
||||
};
|
||||
|
||||
// sizeof() ~ 12
|
||||
// sizeof() ~ 16
|
||||
struct ImGuiTableColumnSettings
|
||||
{
|
||||
float WidthOrWeight;
|
||||
@@ -2939,7 +2956,7 @@ struct ImGuiTableColumnSettings
|
||||
ImGuiTableColumnIdx DisplayOrder;
|
||||
ImGuiTableColumnIdx SortOrder;
|
||||
ImU8 SortDirection : 2;
|
||||
ImU8 IsEnabled : 1; // "Visible" in ini file
|
||||
ImS8 IsEnabled : 2; // "Visible" in ini file
|
||||
ImU8 IsStretch : 1;
|
||||
|
||||
ImGuiTableColumnSettings()
|
||||
@@ -2949,7 +2966,7 @@ struct ImGuiTableColumnSettings
|
||||
Index = -1;
|
||||
DisplayOrder = SortOrder = -1;
|
||||
SortDirection = ImGuiSortDirection_None;
|
||||
IsEnabled = 1;
|
||||
IsEnabled = -1;
|
||||
IsStretch = 0;
|
||||
}
|
||||
};
|
||||
@@ -2980,7 +2997,8 @@ namespace ImGui
|
||||
// If this ever crashes because g.CurrentWindow is NULL, it means that either:
|
||||
// - ImGui::NewFrame() has never been called, which is illegal.
|
||||
// - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.
|
||||
IMGUI_API ImGuiIO& GetIOEx(ImGuiContext* ctx);
|
||||
IMGUI_API ImGuiIO& GetIO(ImGuiContext* ctx);
|
||||
IMGUI_API ImGuiPlatformIO& GetPlatformIO(ImGuiContext* ctx);
|
||||
inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; }
|
||||
inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; }
|
||||
IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id);
|
||||
@@ -3108,7 +3126,7 @@ namespace ImGui
|
||||
IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess);
|
||||
|
||||
// Parameter stacks (shared)
|
||||
IMGUI_API const ImGuiDataVarInfo* GetStyleVarInfo(ImGuiStyleVar idx);
|
||||
IMGUI_API const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx);
|
||||
IMGUI_API void BeginDisabledOverrideReenable();
|
||||
IMGUI_API void EndDisabledOverrideReenable();
|
||||
|
||||
@@ -3123,6 +3141,7 @@ namespace ImGui
|
||||
|
||||
// Popups, Modals
|
||||
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_window_flags);
|
||||
IMGUI_API bool BeginPopupMenuEx(ImGuiID id, const char* label, ImGuiWindowFlags extra_window_flags);
|
||||
IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None);
|
||||
IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup);
|
||||
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup);
|
||||
@@ -3474,6 +3493,7 @@ namespace ImGui
|
||||
inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); }
|
||||
inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active
|
||||
IMGUI_API void SetNextItemRefVal(ImGuiDataType data_type, void* p_data);
|
||||
inline bool IsItemActiveAsInputText() { ImGuiContext& g = *GImGui; return g.ActiveId != 0 && g.ActiveId == g.LastItemData.ID && g.InputTextState.ID == g.LastItemData.ID; } // This may be useful to apply workaround that a based on distinguish whenever an item is active as a text input field.
|
||||
|
||||
// Color
|
||||
IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags);
|
||||
@@ -3569,16 +3589,18 @@ struct ImFontBuilderIO
|
||||
#ifdef IMGUI_ENABLE_STB_TRUETYPE
|
||||
IMGUI_API const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype();
|
||||
#endif
|
||||
IMGUI_API void ImFontAtlasUpdateConfigDataPointers(ImFontAtlas* atlas);
|
||||
IMGUI_API void ImFontAtlasUpdateSourcesPointers(ImFontAtlas* atlas);
|
||||
IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas);
|
||||
IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent);
|
||||
IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, float ascent, float descent);
|
||||
IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque);
|
||||
IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas);
|
||||
IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value);
|
||||
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);
|
||||
IMGUI_API void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* src, int* out_oversample_h, int* out_oversample_v);
|
||||
|
||||
IMGUI_API bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Test Engine specific hooks (imgui_test_engine)
|
||||
|
||||
511
3rdparty/imgui/src/imgui.cpp
vendored
511
3rdparty/imgui/src/imgui.cpp
vendored
File diff suppressed because it is too large
Load Diff
3112
3rdparty/imgui/src/imgui_demo.cpp
vendored
3112
3rdparty/imgui/src/imgui_demo.cpp
vendored
File diff suppressed because it is too large
Load Diff
188
3rdparty/imgui/src/imgui_draw.cpp
vendored
188
3rdparty/imgui/src/imgui_draw.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.8
|
||||
// dear imgui, v1.91.9b
|
||||
// (drawing and font code)
|
||||
|
||||
/*
|
||||
@@ -68,6 +68,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
|
||||
#pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier
|
||||
#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
|
||||
@@ -143,6 +144,7 @@ namespace IMGUI_STB_NAMESPACE
|
||||
#define STBTT_fabs(x) ImFabs(x)
|
||||
#define STBTT_ifloor(x) ((int)ImFloor(x))
|
||||
#define STBTT_iceil(x) ((int)ImCeil(x))
|
||||
#define STBTT_strlen(x) ImStrlen(x)
|
||||
#define STBTT_STATIC
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#else
|
||||
@@ -374,6 +376,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
|
||||
ImDrawListSharedData::ImDrawListSharedData()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
InitialFringeScale = 1.0f;
|
||||
for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++)
|
||||
{
|
||||
const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx);
|
||||
@@ -433,7 +436,7 @@ void ImDrawList::_ResetForNewFrame()
|
||||
_Path.resize(0);
|
||||
_Splitter.Clear();
|
||||
CmdBuffer.push_back(ImDrawCmd());
|
||||
_FringeScale = 1.0f;
|
||||
_FringeScale = _Data->InitialFringeScale;
|
||||
}
|
||||
|
||||
void ImDrawList::_ClearFreeMemory()
|
||||
@@ -2401,13 +2404,13 @@ ImFontConfig::ImFontConfig()
|
||||
// - ImFontAtlas::AddCustomRectRegular()
|
||||
// - ImFontAtlas::AddCustomRectFontGlyph()
|
||||
// - ImFontAtlas::CalcCustomRectUV()
|
||||
// - ImFontAtlas::GetMouseCursorTexData()
|
||||
// - ImFontAtlasGetMouseCursorTexData()
|
||||
// - ImFontAtlas::Build()
|
||||
// - ImFontAtlasBuildMultiplyCalcLookupTable()
|
||||
// - ImFontAtlasBuildMultiplyRectAlpha8()
|
||||
// - ImFontAtlasBuildWithStbTruetype()
|
||||
// - ImFontAtlasGetBuilderForStbTruetype()
|
||||
// - ImFontAtlasUpdateConfigDataPointers()
|
||||
// - ImFontAtlasUpdateSourcesPointers()
|
||||
// - ImFontAtlasBuildSetupFont()
|
||||
// - ImFontAtlasBuildPackCustomRects()
|
||||
// - ImFontAtlasBuildRender8bppRectFromString()
|
||||
@@ -2465,6 +2468,8 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3
|
||||
{ ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
|
||||
{ ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
|
||||
{ ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
|
||||
{ ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Wait // Arrow + custom code in ImGui::RenderMouseCursor()
|
||||
{ ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Progress // Arrow + custom code in ImGui::RenderMouseCursor()
|
||||
{ ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed
|
||||
};
|
||||
|
||||
@@ -2484,7 +2489,7 @@ ImFontAtlas::~ImFontAtlas()
|
||||
void ImFontAtlas::ClearInputData()
|
||||
{
|
||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||
for (ImFontConfig& font_cfg : ConfigData)
|
||||
for (ImFontConfig& font_cfg : Sources)
|
||||
if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas)
|
||||
{
|
||||
IM_FREE(font_cfg.FontData);
|
||||
@@ -2493,12 +2498,12 @@ void ImFontAtlas::ClearInputData()
|
||||
|
||||
// When clearing this we lose access to the font name and other information used to build the font.
|
||||
for (ImFont* font : Fonts)
|
||||
if (font->ConfigData >= ConfigData.Data && font->ConfigData < ConfigData.Data + ConfigData.Size)
|
||||
if (font->Sources >= Sources.Data && font->Sources < Sources.Data + Sources.Size)
|
||||
{
|
||||
font->ConfigData = NULL;
|
||||
font->ConfigDataCount = 0;
|
||||
font->Sources = NULL;
|
||||
font->SourcesCount = 0;
|
||||
}
|
||||
ConfigData.clear();
|
||||
Sources.clear();
|
||||
CustomRects.clear();
|
||||
PackIdMouseCursors = PackIdLines = -1;
|
||||
// Important: we leave TexReady untouched
|
||||
@@ -2581,8 +2586,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
|
||||
else
|
||||
IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
|
||||
|
||||
ConfigData.push_back(*font_cfg);
|
||||
ImFontConfig& new_font_cfg = ConfigData.back();
|
||||
Sources.push_back(*font_cfg);
|
||||
ImFontConfig& new_font_cfg = Sources.back();
|
||||
if (new_font_cfg.DstFont == NULL)
|
||||
new_font_cfg.DstFont = Fonts.back();
|
||||
if (!new_font_cfg.FontDataOwnedByAtlas)
|
||||
@@ -2598,8 +2603,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
|
||||
// - We may support it better later and remove this rounding.
|
||||
new_font_cfg.SizePixels = ImTrunc(new_font_cfg.SizePixels);
|
||||
|
||||
// Pointers to ConfigData and BuilderData are otherwise dangling
|
||||
ImFontAtlasUpdateConfigDataPointers(this);
|
||||
// Pointers to Sources data are otherwise dangling
|
||||
ImFontAtlasUpdateSourcesPointers(this);
|
||||
|
||||
// Invalidate texture
|
||||
TexReady = false;
|
||||
@@ -2669,7 +2674,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels,
|
||||
{
|
||||
// Store a short copy of filename into into the font name for convenience
|
||||
const char* p;
|
||||
for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
|
||||
for (p = filename + ImStrlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
|
||||
ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels);
|
||||
}
|
||||
return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges);
|
||||
@@ -2704,7 +2709,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_d
|
||||
|
||||
ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
|
||||
{
|
||||
int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
|
||||
int compressed_ttf_size = (((int)ImStrlen(compressed_ttf_data_base85) + 4) / 5) * 4;
|
||||
void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
|
||||
Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
|
||||
ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
|
||||
@@ -2751,24 +2756,24 @@ void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* ou
|
||||
*out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y);
|
||||
}
|
||||
|
||||
bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
|
||||
bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
|
||||
{
|
||||
if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT)
|
||||
return false;
|
||||
if (Flags & ImFontAtlasFlags_NoMouseCursors)
|
||||
if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors)
|
||||
return false;
|
||||
|
||||
IM_ASSERT(PackIdMouseCursors != -1);
|
||||
ImFontAtlasCustomRect* r = GetCustomRectByIndex(PackIdMouseCursors);
|
||||
IM_ASSERT(atlas->PackIdMouseCursors != -1);
|
||||
ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors);
|
||||
ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y);
|
||||
ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1];
|
||||
*out_size = size;
|
||||
*out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2];
|
||||
out_uv_border[0] = (pos) * TexUvScale;
|
||||
out_uv_border[1] = (pos + size) * TexUvScale;
|
||||
out_uv_border[0] = (pos) * atlas->TexUvScale;
|
||||
out_uv_border[1] = (pos + size) * atlas->TexUvScale;
|
||||
pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
|
||||
out_uv_fill[0] = (pos) * TexUvScale;
|
||||
out_uv_fill[1] = (pos + size) * TexUvScale;
|
||||
out_uv_fill[0] = (pos) * atlas->TexUvScale;
|
||||
out_uv_fill[1] = (pos + size) * atlas->TexUvScale;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2777,7 +2782,7 @@ bool ImFontAtlas::Build()
|
||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||
|
||||
// Default font is none are specified
|
||||
if (ConfigData.Size == 0)
|
||||
if (Sources.Size == 0)
|
||||
AddFontDefault();
|
||||
|
||||
// Select builder
|
||||
@@ -2819,11 +2824,11 @@ void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig
|
||||
*data = table[*data];
|
||||
}
|
||||
|
||||
void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v)
|
||||
void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* src, 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;
|
||||
*out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : (src->SizePixels * src->RasterizerDensity > 36.0f || src->PixelSnapH) ? 1 : 2;
|
||||
*out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1;
|
||||
}
|
||||
|
||||
#ifdef IMGUI_ENABLE_STB_TRUETYPE
|
||||
@@ -2866,7 +2871,7 @@ static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector<int>*
|
||||
|
||||
static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
{
|
||||
IM_ASSERT(atlas->ConfigData.Size > 0);
|
||||
IM_ASSERT(atlas->Sources.Size > 0);
|
||||
|
||||
ImFontAtlasBuildInit(atlas);
|
||||
|
||||
@@ -2880,32 +2885,32 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
// Temporary storage for building
|
||||
ImVector<ImFontBuildSrcData> src_tmp_array;
|
||||
ImVector<ImFontBuildDstData> dst_tmp_array;
|
||||
src_tmp_array.resize(atlas->ConfigData.Size);
|
||||
src_tmp_array.resize(atlas->Sources.Size);
|
||||
dst_tmp_array.resize(atlas->Fonts.Size);
|
||||
memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
|
||||
memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
|
||||
|
||||
// 1. Initialize font loading structure, check font data validity
|
||||
for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
|
||||
for (int src_i = 0; src_i < atlas->Sources.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
IM_ASSERT(src.DstFont && (!src.DstFont->IsLoaded() || src.DstFont->ContainerAtlas == atlas));
|
||||
|
||||
// Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||
// Find index from src.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||
src_tmp.DstIndex = -1;
|
||||
for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
|
||||
if (cfg.DstFont == atlas->Fonts[output_i])
|
||||
if (src.DstFont == atlas->Fonts[output_i])
|
||||
src_tmp.DstIndex = output_i;
|
||||
if (src_tmp.DstIndex == -1)
|
||||
{
|
||||
IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
|
||||
IM_ASSERT(src_tmp.DstIndex != -1); // src.DstFont not pointing within atlas->Fonts[] array?
|
||||
return false;
|
||||
}
|
||||
// Initialize helper structure for font loading and verify that the TTF/OTF data is correct
|
||||
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
|
||||
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)src.FontData, src.FontNo);
|
||||
IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
|
||||
if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
|
||||
if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)src.FontData, font_offset))
|
||||
{
|
||||
IM_ASSERT(0 && "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize.");
|
||||
return false;
|
||||
@@ -2913,7 +2918,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
|
||||
// Measure highest codepoints
|
||||
ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||
src_tmp.SrcRanges = src.GlyphRanges ? src.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||
{
|
||||
// Check for valid range. This may also help detect *some* dangling pointers, because a common
|
||||
@@ -2992,12 +2997,12 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
buf_packedchars_out_n += src_tmp.GlyphsCount;
|
||||
|
||||
// Automatic selection of oversampling parameters
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
int oversample_h, oversample_v;
|
||||
ImFontAtlasBuildGetOversampleFactors(&cfg, &oversample_h, &oversample_v);
|
||||
ImFontAtlasBuildGetOversampleFactors(&src, &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.font_size = src.SizePixels * src.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;
|
||||
@@ -3006,7 +3011,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
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);
|
||||
const float scale = (src.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, src.SizePixels * src.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -src.SizePixels * src.RasterizerDensity);
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
||||
{
|
||||
int x0, y0, x1, y1;
|
||||
@@ -3066,7 +3071,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
// 8. Render/rasterize font characters into the texture
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
{
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||
if (src_tmp.GlyphsCount == 0)
|
||||
continue;
|
||||
@@ -3074,10 +3079,10 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects);
|
||||
|
||||
// Apply multiply operator
|
||||
if (cfg.RasterizerMultiply != 1.0f)
|
||||
if (src.RasterizerMultiply != 1.0f)
|
||||
{
|
||||
unsigned char multiply_table[256];
|
||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, src.RasterizerMultiply);
|
||||
stbrp_rect* r = &src_tmp.Rects[0];
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++)
|
||||
if (r->was_packed)
|
||||
@@ -3095,22 +3100,22 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
{
|
||||
// When merging fonts with MergeMode=true:
|
||||
// - We can have multiple input fonts writing into a same destination font.
|
||||
// - dst_font->ConfigData is != from cfg which is our source configuration.
|
||||
// - dst_font->Sources is != from src which is our source configuration.
|
||||
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFont* dst_font = cfg.DstFont;
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
ImFont* dst_font = src.DstFont;
|
||||
|
||||
const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels);
|
||||
const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, src.SizePixels);
|
||||
int unscaled_ascent, unscaled_descent, unscaled_line_gap;
|
||||
stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
|
||||
|
||||
const float ascent = ImCeil(unscaled_ascent * font_scale);
|
||||
const float descent = ImFloor(unscaled_descent * font_scale);
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
|
||||
const float font_off_x = cfg.GlyphOffset.x;
|
||||
const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &src, ascent, descent);
|
||||
const float font_off_x = src.GlyphOffset.x;
|
||||
const float font_off_y = src.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||
|
||||
const float inv_rasterization_scale = 1.0f / cfg.RasterizerDensity;
|
||||
const float inv_rasterization_scale = 1.0f / src.RasterizerDensity;
|
||||
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||
{
|
||||
@@ -3124,7 +3129,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
float y0 = q.y0 * inv_rasterization_scale + font_off_y;
|
||||
float x1 = q.x1 * inv_rasterization_scale + font_off_x;
|
||||
float y1 = q.y1 * inv_rasterization_scale + font_off_y;
|
||||
dst_font->AddGlyph(&cfg, (ImWchar)codepoint, x0, y0, x1, y1, q.s0, q.t0, q.s1, q.t1, pc.xadvance * inv_rasterization_scale);
|
||||
dst_font->AddGlyph(&src, (ImWchar)codepoint, x0, y0, x1, y1, q.s0, q.t0, q.s1, q.t1, pc.xadvance * inv_rasterization_scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3144,17 +3149,17 @@ const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype()
|
||||
|
||||
#endif // IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
void ImFontAtlasUpdateConfigDataPointers(ImFontAtlas* atlas)
|
||||
void ImFontAtlasUpdateSourcesPointers(ImFontAtlas* atlas)
|
||||
{
|
||||
for (ImFontConfig& font_cfg : atlas->ConfigData)
|
||||
for (ImFontConfig& src : atlas->Sources)
|
||||
{
|
||||
ImFont* font = font_cfg.DstFont;
|
||||
if (!font_cfg.MergeMode)
|
||||
ImFont* font = src.DstFont;
|
||||
if (!src.MergeMode)
|
||||
{
|
||||
font->ConfigData = &font_cfg;
|
||||
font->ConfigDataCount = 0;
|
||||
font->Sources = &src;
|
||||
font->SourcesCount = 0;
|
||||
}
|
||||
font->ConfigDataCount++;
|
||||
font->SourcesCount++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3164,7 +3169,7 @@ void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* f
|
||||
{
|
||||
font->ClearOutputData();
|
||||
font->FontSize = font_config->SizePixels;
|
||||
IM_ASSERT(font->ConfigData == font_config);
|
||||
IM_ASSERT(font->Sources == font_config);
|
||||
font->ContainerAtlas = atlas;
|
||||
font->Ascent = ascent;
|
||||
font->Descent = descent;
|
||||
@@ -3349,7 +3354,7 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
|
||||
if (r->Font == NULL || r->GlyphID == 0)
|
||||
continue;
|
||||
|
||||
// Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, GlyphExtraSpacing, PixelSnapH
|
||||
// Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, PixelSnapH
|
||||
IM_ASSERT(r->Font->ContainerAtlas == atlas);
|
||||
ImVec2 uv0, uv1;
|
||||
atlas->CalcCustomRectUV(r, &uv0, &uv1);
|
||||
@@ -3685,21 +3690,8 @@ void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
|
||||
|
||||
ImFont::ImFont()
|
||||
{
|
||||
FontSize = 0.0f;
|
||||
FallbackAdvanceX = 0.0f;
|
||||
FallbackChar = 0;
|
||||
EllipsisChar = 0;
|
||||
EllipsisWidth = EllipsisCharStep = 0.0f;
|
||||
EllipsisCharCount = 0;
|
||||
FallbackGlyph = NULL;
|
||||
ContainerAtlas = NULL;
|
||||
ConfigData = NULL;
|
||||
ConfigDataCount = 0;
|
||||
DirtyLookupTables = false;
|
||||
memset(this, 0, sizeof(*this));
|
||||
Scale = 1.0f;
|
||||
Ascent = Descent = 0.0f;
|
||||
MetricsTotalSurface = 0;
|
||||
memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap));
|
||||
}
|
||||
|
||||
ImFont::~ImFont()
|
||||
@@ -3770,8 +3762,10 @@ void ImFont::BuildLookupTable()
|
||||
}
|
||||
|
||||
// Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons)
|
||||
SetGlyphVisible((ImWchar)' ', false);
|
||||
SetGlyphVisible((ImWchar)'\t', false);
|
||||
if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)' '))
|
||||
glyph->Visible = false;
|
||||
if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)'\t'))
|
||||
glyph->Visible = false;
|
||||
|
||||
// Setup Fallback character
|
||||
const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };
|
||||
@@ -3794,7 +3788,7 @@ void ImFont::BuildLookupTable()
|
||||
// Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
|
||||
// However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
|
||||
// FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots.
|
||||
const ImWchar ellipsis_chars[] = { ConfigData->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 };
|
||||
const ImWchar ellipsis_chars[] = { Sources->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 };
|
||||
const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };
|
||||
if (EllipsisChar == 0)
|
||||
EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars));
|
||||
@@ -3827,12 +3821,6 @@ bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImFont::SetGlyphVisible(ImWchar c, bool visible)
|
||||
{
|
||||
if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c))
|
||||
glyph->Visible = visible ? 1 : 0;
|
||||
}
|
||||
|
||||
void ImFont::GrowIndex(int new_size)
|
||||
{
|
||||
IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
|
||||
@@ -3844,27 +3832,27 @@ void ImFont::GrowIndex(int new_size)
|
||||
|
||||
// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
|
||||
// Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis).
|
||||
// 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font.
|
||||
void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x)
|
||||
// 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font.
|
||||
void ImFont::AddGlyph(const ImFontConfig* src, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x)
|
||||
{
|
||||
if (cfg != NULL)
|
||||
if (src != NULL)
|
||||
{
|
||||
// Clamp & recenter if needed
|
||||
const float advance_x_original = advance_x;
|
||||
advance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX);
|
||||
advance_x = ImClamp(advance_x, src->GlyphMinAdvanceX, src->GlyphMaxAdvanceX);
|
||||
if (advance_x != advance_x_original)
|
||||
{
|
||||
float char_off_x = cfg->PixelSnapH ? ImTrunc((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f;
|
||||
float char_off_x = src->PixelSnapH ? ImTrunc((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f;
|
||||
x0 += char_off_x;
|
||||
x1 += char_off_x;
|
||||
}
|
||||
|
||||
// Snap to pixel
|
||||
if (cfg->PixelSnapH)
|
||||
if (src->PixelSnapH)
|
||||
advance_x = IM_ROUND(advance_x);
|
||||
|
||||
// Bake spacing
|
||||
advance_x += cfg->GlyphExtraSpacing.x;
|
||||
// Bake extra spacing
|
||||
advance_x += src->GlyphExtraAdvanceX;
|
||||
}
|
||||
|
||||
int glyph_idx = Glyphs.Size;
|
||||
@@ -3907,7 +3895,7 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
|
||||
}
|
||||
|
||||
// Find glyph, return fallback if missing
|
||||
const ImFontGlyph* ImFont::FindGlyph(ImWchar c)
|
||||
ImFontGlyph* ImFont::FindGlyph(ImWchar c)
|
||||
{
|
||||
if (c >= (size_t)IndexLookup.Size)
|
||||
return FallbackGlyph;
|
||||
@@ -3917,7 +3905,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c)
|
||||
return &Glyphs.Data[i];
|
||||
}
|
||||
|
||||
const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c)
|
||||
ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c)
|
||||
{
|
||||
if (c >= (size_t)IndexLookup.Size)
|
||||
return NULL;
|
||||
@@ -4043,7 +4031,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
|
||||
ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining)
|
||||
{
|
||||
if (!text_end)
|
||||
text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this.
|
||||
text_end = text_begin + ImStrlen(text_begin); // FIXME-OPT: Need to avoid this.
|
||||
|
||||
const float line_height = size;
|
||||
const float scale = size / FontSize;
|
||||
@@ -4143,7 +4131,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
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.
|
||||
text_end = text_begin + ImStrlen(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;
|
||||
@@ -4155,7 +4143,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
if (y + line_height < clip_rect.y)
|
||||
while (y + line_height < clip_rect.y && s < text_end)
|
||||
{
|
||||
const char* line_end = (const char*)memchr(s, '\n', text_end - s);
|
||||
const char* line_end = (const char*)ImMemchr(s, '\n', text_end - s);
|
||||
if (word_wrap_enabled)
|
||||
{
|
||||
// FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA().
|
||||
@@ -4179,7 +4167,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
float y_end = y;
|
||||
while (y_end < clip_rect.w && s_end < text_end)
|
||||
{
|
||||
s_end = (const char*)memchr(s_end, '\n', text_end - s_end);
|
||||
s_end = (const char*)ImMemchr(s_end, '\n', text_end - s_end);
|
||||
s_end = s_end ? s_end + 1 : text_end;
|
||||
y_end += line_height;
|
||||
}
|
||||
|
||||
64
3rdparty/imgui/src/imgui_freetype.cpp
vendored
64
3rdparty/imgui/src/imgui_freetype.cpp
vendored
@@ -166,7 +166,7 @@ namespace
|
||||
// NB: No ctor/dtor, explicitly call Init()/Shutdown()
|
||||
struct FreeTypeFont
|
||||
{
|
||||
bool InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
|
||||
bool InitFont(FT_Library ft_library, const ImFontConfig& src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
|
||||
void CloseFont();
|
||||
void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
|
||||
const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint);
|
||||
@@ -185,9 +185,9 @@ namespace
|
||||
float InvRasterizationDensity;
|
||||
};
|
||||
|
||||
bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_font_builder_flags)
|
||||
bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& src, 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);
|
||||
FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src.FontData, (uint32_t)src.FontDataSize, (uint32_t)src.FontNo, &Face);
|
||||
if (error != 0)
|
||||
return false;
|
||||
error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE);
|
||||
@@ -195,7 +195,7 @@ namespace
|
||||
return false;
|
||||
|
||||
// Convert to FreeType flags (NB: Bold and Oblique are processed separately)
|
||||
UserFlags = cfg.FontBuilderFlags | extra_font_builder_flags;
|
||||
UserFlags = src.FontBuilderFlags | extra_font_builder_flags;
|
||||
|
||||
LoadFlags = 0;
|
||||
if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0)
|
||||
@@ -222,11 +222,11 @@ namespace
|
||||
if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor)
|
||||
LoadFlags |= FT_LOAD_COLOR;
|
||||
|
||||
RasterizationDensity = cfg.RasterizerDensity;
|
||||
RasterizationDensity = src.RasterizerDensity;
|
||||
InvRasterizationDensity = 1.0f / RasterizationDensity;
|
||||
|
||||
memset(&Info, 0, sizeof(Info));
|
||||
SetPixelHeight((uint32_t)cfg.SizePixels);
|
||||
SetPixelHeight((uint32_t)src.SizePixels);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -269,11 +269,11 @@ namespace
|
||||
if (glyph_index == 0)
|
||||
return nullptr;
|
||||
|
||||
// If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts.
|
||||
// - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076
|
||||
// - https://github.com/ocornut/imgui/issues/4567
|
||||
// - https://github.com/ocornut/imgui/issues/4566
|
||||
// You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version.
|
||||
// If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts.
|
||||
// - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076
|
||||
// - https://github.com/ocornut/imgui/issues/4567
|
||||
// - https://github.com/ocornut/imgui/issues/4566
|
||||
// You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version.
|
||||
FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags);
|
||||
if (error)
|
||||
return nullptr;
|
||||
@@ -443,7 +443,7 @@ struct ImFontBuildDstDataFT
|
||||
|
||||
bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags)
|
||||
{
|
||||
IM_ASSERT(atlas->ConfigData.Size > 0);
|
||||
IM_ASSERT(atlas->Sources.Size > 0);
|
||||
|
||||
ImFontAtlasBuildInit(atlas);
|
||||
|
||||
@@ -458,36 +458,36 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
bool src_load_color = false;
|
||||
ImVector<ImFontBuildSrcDataFT> src_tmp_array;
|
||||
ImVector<ImFontBuildDstDataFT> dst_tmp_array;
|
||||
src_tmp_array.resize(atlas->ConfigData.Size);
|
||||
src_tmp_array.resize(atlas->Sources.Size);
|
||||
dst_tmp_array.resize(atlas->Fonts.Size);
|
||||
memset((void*)src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
|
||||
memset((void*)dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
|
||||
|
||||
// 1. Initialize font loading structure, check font data validity
|
||||
for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
|
||||
for (int src_i = 0; src_i < atlas->Sources.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
FreeTypeFont& font_face = src_tmp.Font;
|
||||
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
||||
IM_ASSERT(src.DstFont && (!src.DstFont->IsLoaded() || src.DstFont->ContainerAtlas == atlas));
|
||||
|
||||
// Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||
// Find index from src.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||
src_tmp.DstIndex = -1;
|
||||
for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
|
||||
if (cfg.DstFont == atlas->Fonts[output_i])
|
||||
if (src.DstFont == atlas->Fonts[output_i])
|
||||
src_tmp.DstIndex = output_i;
|
||||
IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
|
||||
IM_ASSERT(src_tmp.DstIndex != -1); // src.DstFont not pointing within atlas->Fonts[] array?
|
||||
if (src_tmp.DstIndex == -1)
|
||||
return false;
|
||||
|
||||
// Load font
|
||||
if (!font_face.InitFont(ft_library, cfg, extra_flags))
|
||||
if (!font_face.InitFont(ft_library, src, extra_flags))
|
||||
return false;
|
||||
|
||||
// Measure highest codepoints
|
||||
src_load_color |= (cfg.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0;
|
||||
src_load_color |= (src.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0;
|
||||
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||
src_tmp.SrcRanges = src.GlyphRanges ? src.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||
{
|
||||
// Check for valid range. This may also help detect *some* dangling pointers, because a common
|
||||
@@ -577,7 +577,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
if (src_tmp.GlyphsCount == 0)
|
||||
continue;
|
||||
|
||||
@@ -585,10 +585,10 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
buf_rects_out_n += src_tmp.GlyphsCount;
|
||||
|
||||
// Compute multiply table if requested
|
||||
const bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);
|
||||
const bool multiply_enabled = (src.RasterizerMultiply != 1.0f);
|
||||
unsigned char multiply_table[256];
|
||||
if (multiply_enabled)
|
||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, src.RasterizerMultiply);
|
||||
|
||||
// Gather the sizes of all rectangles we will need to pack
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
||||
@@ -687,18 +687,18 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
|
||||
// When merging fonts with MergeMode=true:
|
||||
// - We can have multiple input fonts writing into a same destination font.
|
||||
// - dst_font->ConfigData is != from cfg which is our source configuration.
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFont* dst_font = cfg.DstFont;
|
||||
// - dst_font->Sources is != from src which is our source configuration.
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
ImFont* dst_font = src.DstFont;
|
||||
|
||||
const float ascent = src_tmp.Font.Info.Ascender;
|
||||
const float descent = src_tmp.Font.Info.Descender;
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &src, ascent, descent);
|
||||
|
||||
if (src_tmp.GlyphsCount == 0)
|
||||
continue;
|
||||
const float font_off_x = cfg.GlyphOffset.x;
|
||||
const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||
const float font_off_x = src.GlyphOffset.x;
|
||||
const float font_off_y = src.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||
|
||||
const int padding = atlas->TexGlyphPadding;
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||
@@ -724,7 +724,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
float v0 = (ty) / (float)atlas->TexHeight;
|
||||
float u1 = (tx + info.Width) / (float)atlas->TexWidth;
|
||||
float v1 = (ty + info.Height) / (float)atlas->TexHeight;
|
||||
dst_font->AddGlyph(&cfg, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX * src_tmp.Font.InvRasterizationDensity);
|
||||
dst_font->AddGlyph(&src, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX * src_tmp.Font.InvRasterizationDensity);
|
||||
|
||||
ImFontGlyph* dst_glyph = &dst_font->Glyphs.back();
|
||||
IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint);
|
||||
|
||||
94
3rdparty/imgui/src/imgui_tables.cpp
vendored
94
3rdparty/imgui/src/imgui_tables.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.8
|
||||
// dear imgui, v1.91b
|
||||
// (tables and columns code)
|
||||
|
||||
/*
|
||||
@@ -221,6 +221,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
|
||||
#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int'
|
||||
#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
|
||||
@@ -230,6 +231,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
|
||||
#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
|
||||
@@ -340,6 +342,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
{
|
||||
ItemSize(outer_rect);
|
||||
ItemAdd(outer_rect, id);
|
||||
g.NextWindowData.ClearFlags();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -415,12 +418,15 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
|
||||
// Reset scroll if we are reactivating it
|
||||
if ((previous_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0)
|
||||
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) == 0)
|
||||
if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasScroll) == 0)
|
||||
SetNextWindowScroll(ImVec2(0.0f, 0.0f));
|
||||
|
||||
// Create scrolling region (without border and zero window padding)
|
||||
ImGuiWindowFlags child_window_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;
|
||||
BeginChildEx(name, instance_id, outer_rect.GetSize(), ImGuiChildFlags_None, child_window_flags);
|
||||
ImGuiChildFlags child_child_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) ? g.NextWindowData.ChildFlags : ImGuiChildFlags_None;
|
||||
ImGuiWindowFlags child_window_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasWindowFlags) ? g.NextWindowData.WindowFlags : ImGuiWindowFlags_None;
|
||||
if (flags & ImGuiTableFlags_ScrollX)
|
||||
child_window_flags |= ImGuiWindowFlags_HorizontalScrollbar;
|
||||
BeginChildEx(name, instance_id, outer_rect.GetSize(), child_child_flags, child_window_flags);
|
||||
table->InnerWindow = g.CurrentWindow;
|
||||
table->WorkRect = table->InnerWindow->WorkRect;
|
||||
table->OuterRect = table->InnerWindow->Rect();
|
||||
@@ -573,6 +579,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
// Initialize
|
||||
table->SettingsOffset = -1;
|
||||
table->IsSortSpecsDirty = true;
|
||||
table->IsSettingsDirty = true; // Records itself into .ini file even when in default state (#7934)
|
||||
table->InstanceInteracted = -1;
|
||||
table->ContextPopupColumn = -1;
|
||||
table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1;
|
||||
@@ -972,7 +979,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
// [Part 4] Apply final widths based on requested widths
|
||||
const ImRect work_rect = table->WorkRect;
|
||||
const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);
|
||||
const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synched tables with mismatching scrollbar state (#5920)
|
||||
const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synced tables with mismatching scrollbar state (#5920)
|
||||
const float width_avail = ImMax(1.0f, (((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth()) - width_removed);
|
||||
const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests;
|
||||
float width_remaining_for_stretched_columns = width_avail_for_stretched_columns;
|
||||
@@ -1385,7 +1392,7 @@ void ImGui::EndTable()
|
||||
|
||||
// Setup inner scrolling range
|
||||
// FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y,
|
||||
// but since the later is likely to be impossible to do we'd rather update both axises together.
|
||||
// but since the later is likely to be impossible to do we'd rather update both axes together.
|
||||
if (table->Flags & ImGuiTableFlags_ScrollX)
|
||||
{
|
||||
const float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f;
|
||||
@@ -1560,6 +1567,31 @@ void ImGui::EndTable()
|
||||
NavUpdateCurrentWindowIsScrollPushableX();
|
||||
}
|
||||
|
||||
// Called in TableSetupColumn() when initializing and in TableLoadSettings() for defaults before applying stored settings.
|
||||
// 'init_mask' specify which fields to initialize.
|
||||
static void TableInitColumnDefaults(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags init_mask)
|
||||
{
|
||||
ImGuiTableColumnFlags flags = column->Flags;
|
||||
if (init_mask & ImGuiTableFlags_Resizable)
|
||||
{
|
||||
float init_width_or_weight = column->InitStretchWeightOrWidth;
|
||||
column->WidthRequest = ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f;
|
||||
column->StretchWeight = (init_width_or_weight > 0.0f && (flags & ImGuiTableColumnFlags_WidthStretch)) ? init_width_or_weight : -1.0f;
|
||||
if (init_width_or_weight > 0.0f) // Disable auto-fit if an explicit width/weight has been specified
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
if (init_mask & ImGuiTableFlags_Reorderable)
|
||||
column->DisplayOrder = (ImGuiTableColumnIdx)table->Columns.index_from_ptr(column);
|
||||
if (init_mask & ImGuiTableFlags_Hideable)
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = (flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1;
|
||||
if (init_mask & ImGuiTableFlags_Sortable)
|
||||
{
|
||||
// Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
|
||||
column->SortOrder = (flags & ImGuiTableColumnFlags_DefaultSort) ? 0 : -1;
|
||||
column->SortDirection = (flags & ImGuiTableColumnFlags_DefaultSort) ? ((flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending)) : (ImS8)ImGuiSortDirection_None;
|
||||
}
|
||||
}
|
||||
|
||||
// See "COLUMNS SIZING POLICIES" comments at the top of this file
|
||||
// If (init_width_or_weight <= 0.0f) it is ignored
|
||||
void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id)
|
||||
@@ -1588,7 +1620,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
|
||||
IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitly in either Table or Column.");
|
||||
|
||||
// When passing a width automatically enforce WidthFixed policy
|
||||
// (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable)
|
||||
// (whereas TableSetupColumnFlags would default to WidthAuto if table is not resizable)
|
||||
if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0 && init_width_or_weight > 0.0f)
|
||||
if ((table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedFit || (table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame)
|
||||
flags |= ImGuiTableColumnFlags_WidthFixed;
|
||||
@@ -1606,27 +1638,10 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
|
||||
column->InitStretchWeightOrWidth = init_width_or_weight;
|
||||
if (table->IsInitializing)
|
||||
{
|
||||
// Init width or weight
|
||||
ImGuiTableFlags init_flags = ~table->SettingsLoadedFlags;
|
||||
if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f)
|
||||
{
|
||||
if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f)
|
||||
column->WidthRequest = init_width_or_weight;
|
||||
if (flags & ImGuiTableColumnFlags_WidthStretch)
|
||||
column->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f;
|
||||
|
||||
// Disable auto-fit if an explicit width/weight has been specified
|
||||
if (init_width_or_weight > 0.0f)
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
|
||||
// Init default visibility/sort state
|
||||
if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0)
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = false;
|
||||
if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0)
|
||||
{
|
||||
column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
|
||||
column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending);
|
||||
}
|
||||
init_flags |= ImGuiTableFlags_Resizable;
|
||||
TableInitColumnDefaults(table, column, init_flags);
|
||||
}
|
||||
|
||||
// Store name (append with zero-terminator in contiguous buffer)
|
||||
@@ -1635,7 +1650,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
|
||||
if (label != NULL && label[0] != 0)
|
||||
{
|
||||
column->NameOffset = (ImS16)table->ColumnsNames.size();
|
||||
table->ColumnsNames.append(label, label + strlen(label) + 1);
|
||||
table->ColumnsNames.append(label, label + ImStrlen(label) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2101,7 +2116,11 @@ bool ImGui::TableSetColumnIndex(int column_n)
|
||||
{
|
||||
if (table->CurrentColumn != -1)
|
||||
TableEndCell(table);
|
||||
IM_ASSERT(column_n >= 0 && table->ColumnsCount);
|
||||
if ((column_n >= 0 && column_n < table->ColumnsCount) == false)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(column_n >= 0 && column_n < table->ColumnsCount, "TableSetColumnIndex() invalid column index!");
|
||||
return false;
|
||||
}
|
||||
TableBeginCell(table, column_n);
|
||||
}
|
||||
|
||||
@@ -3714,6 +3733,14 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
|
||||
table->SettingsLoadedFlags = settings->SaveFlags;
|
||||
table->RefScale = settings->RefScale;
|
||||
|
||||
// Initialize default columns settings
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
{
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
TableInitColumnDefaults(table, column, ~0);
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
|
||||
// Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn
|
||||
ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings();
|
||||
ImU64 display_order_mask = 0;
|
||||
@@ -3730,14 +3757,12 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
|
||||
column->StretchWeight = column_settings->WidthOrWeight;
|
||||
else
|
||||
column->WidthRequest = column_settings->WidthOrWeight;
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
if (settings->SaveFlags & ImGuiTableFlags_Reorderable)
|
||||
column->DisplayOrder = column_settings->DisplayOrder;
|
||||
else
|
||||
column->DisplayOrder = (ImGuiTableColumnIdx)column_n;
|
||||
display_order_mask |= (ImU64)1 << column->DisplayOrder;
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled;
|
||||
if ((settings->SaveFlags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1)
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled == 1;
|
||||
column->SortOrder = column_settings->SortOrder;
|
||||
column->SortDirection = column_settings->SortDirection;
|
||||
}
|
||||
@@ -3833,8 +3858,7 @@ static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandle
|
||||
const bool save_visible = (settings->SaveFlags & ImGuiTableFlags_Hideable) != 0;
|
||||
const bool save_order = (settings->SaveFlags & ImGuiTableFlags_Reorderable) != 0;
|
||||
const bool save_sort = (settings->SaveFlags & ImGuiTableFlags_Sortable) != 0;
|
||||
if (!save_size && !save_visible && !save_order && !save_sort)
|
||||
continue;
|
||||
// We need to save the [Table] entry even if all the bools are false, since this records a table with "default settings".
|
||||
|
||||
buf->reserve(buf->size() + 30 + settings->ColumnsCount * 50); // ballpark reserve
|
||||
buf->appendf("[%s][0x%08X,%d]\n", handler->TypeName, settings->ID, settings->ColumnsCount);
|
||||
|
||||
173
3rdparty/imgui/src/imgui_widgets.cpp
vendored
173
3rdparty/imgui/src/imgui_widgets.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.8
|
||||
// dear imgui, v1.91b
|
||||
// (widgets code)
|
||||
|
||||
/*
|
||||
@@ -70,6 +70,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
|
||||
#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int'
|
||||
#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used.
|
||||
@@ -80,6 +81,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
|
||||
#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
|
||||
@@ -169,7 +171,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
|
||||
// Calculate length
|
||||
const char* text_begin = text;
|
||||
if (text_end == NULL)
|
||||
text_end = text + strlen(text); // FIXME-OPT
|
||||
text_end = text + ImStrlen(text); // FIXME-OPT
|
||||
|
||||
const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
|
||||
const float wrap_pos_x = window->DC.TextWrapPos;
|
||||
@@ -209,7 +211,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
|
||||
int lines_skipped = 0;
|
||||
while (line < text_end && lines_skipped < lines_skippable)
|
||||
{
|
||||
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
|
||||
const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line);
|
||||
if (!line_end)
|
||||
line_end = text_end;
|
||||
if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)
|
||||
@@ -230,7 +232,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
|
||||
if (IsClippedEx(line_rect, 0))
|
||||
break;
|
||||
|
||||
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
|
||||
const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line);
|
||||
if (!line_end)
|
||||
line_end = text_end;
|
||||
text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x);
|
||||
@@ -245,7 +247,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
|
||||
int lines_skipped = 0;
|
||||
while (line < text_end)
|
||||
{
|
||||
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
|
||||
const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line);
|
||||
if (!line_end)
|
||||
line_end = text_end;
|
||||
if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)
|
||||
@@ -913,7 +915,7 @@ ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis)
|
||||
const ImRect outer_rect = window->Rect();
|
||||
const ImRect inner_rect = window->InnerRect;
|
||||
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);
|
||||
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)
|
||||
@@ -971,8 +973,8 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6
|
||||
|
||||
// When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the window resize grab)
|
||||
float alpha = 1.0f;
|
||||
if ((axis == ImGuiAxis_Y) && bb_frame_height < g.FontSize + g.Style.FramePadding.y * 2.0f)
|
||||
alpha = ImSaturate((bb_frame_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f));
|
||||
if ((axis == ImGuiAxis_Y) && bb_frame_height < bb_frame_width)
|
||||
alpha = ImSaturate(bb_frame_height / ImMax(bb_frame_width * 2.0f, 1.0f));
|
||||
if (alpha <= 0.0f)
|
||||
return false;
|
||||
|
||||
@@ -989,7 +991,8 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6
|
||||
// But we maintain a minimum size in pixel to allow for the user to still aim inside.
|
||||
IM_ASSERT(ImMax(size_contents_v, size_visible_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers.
|
||||
const ImS64 win_size_v = ImMax(ImMax(size_contents_v, size_visible_v), (ImS64)1);
|
||||
const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), style.GrabMinSize, scrollbar_size_v);
|
||||
const float grab_h_minsize = ImMin(bb.GetSize()[axis], style.GrabMinSize);
|
||||
const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), grab_h_minsize, scrollbar_size_v);
|
||||
const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
|
||||
|
||||
// Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
|
||||
@@ -1061,25 +1064,45 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6
|
||||
|
||||
// - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
|
||||
// - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above.
|
||||
void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
|
||||
void ImGui::ImageWithBg(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return;
|
||||
|
||||
const float border_size = (border_col.w > 0.0f) ? 1.0f : 0.0f;
|
||||
const ImVec2 padding(border_size, border_size);
|
||||
const ImVec2 padding(g.Style.ImageBorderSize, g.Style.ImageBorderSize);
|
||||
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + image_size + padding * 2.0f);
|
||||
ItemSize(bb);
|
||||
if (!ItemAdd(bb, 0))
|
||||
return;
|
||||
|
||||
// Render
|
||||
if (border_size > 0.0f)
|
||||
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f, ImDrawFlags_None, border_size);
|
||||
if (g.Style.ImageBorderSize > 0.0f)
|
||||
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border), 0.0f, ImDrawFlags_None, g.Style.ImageBorderSize);
|
||||
if (bg_col.w > 0.0f)
|
||||
window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col));
|
||||
window->DrawList->AddImage(user_texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col));
|
||||
}
|
||||
|
||||
void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1)
|
||||
{
|
||||
ImageWithBg(user_texture_id, image_size, uv0, uv1);
|
||||
}
|
||||
|
||||
// 1.91.9 (February 2025) removed 'tint_col' and 'border_col' parameters, made border size not depend on color value. (#8131, #8238)
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
PushStyleVar(ImGuiStyleVar_ImageBorderSize, (border_col.w > 0.0f) ? ImMax(1.0f, g.Style.ImageBorderSize) : 0.0f); // Preserve legacy behavior where border is always visible when border_col's Alpha is >0.0f
|
||||
PushStyleColor(ImGuiCol_Border, border_col);
|
||||
ImageWithBg(user_texture_id, image_size, uv0, uv1, ImVec4(0, 0, 0, 0), tint_col);
|
||||
PopStyleColor();
|
||||
PopStyleVar();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@@ -1423,7 +1446,7 @@ bool ImGui::TextLink(const char* label)
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const char* label_end = FindRenderedTextEnd(label);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
|
||||
ImVec2 size = CalcTextSize(label, label_end, true);
|
||||
ImRect bb(pos, pos + size);
|
||||
ItemSize(size, 0.0f);
|
||||
@@ -1828,7 +1851,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
|
||||
ImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.Flags;
|
||||
ImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.HasFlags;
|
||||
g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
@@ -1897,7 +1920,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
|
||||
if (!popup_open)
|
||||
return false;
|
||||
|
||||
g.NextWindowData.Flags = backup_next_window_data_flags;
|
||||
g.NextWindowData.HasFlags = backup_next_window_data_flags;
|
||||
return BeginComboPopup(popup_id, bb, flags);
|
||||
}
|
||||
|
||||
@@ -1912,7 +1935,7 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags
|
||||
|
||||
// Set popup size
|
||||
float w = bb.GetWidth();
|
||||
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
|
||||
if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSizeConstraint)
|
||||
{
|
||||
g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w);
|
||||
}
|
||||
@@ -1926,9 +1949,9 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags
|
||||
else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4;
|
||||
else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20;
|
||||
ImVec2 constraint_min(0.0f, 0.0f), constraint_max(FLT_MAX, FLT_MAX);
|
||||
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size
|
||||
if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size
|
||||
constraint_min.x = w;
|
||||
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f)
|
||||
if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f)
|
||||
constraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items);
|
||||
SetNextWindowSizeConstraints(constraint_min, constraint_max);
|
||||
}
|
||||
@@ -2043,7 +2066,7 @@ static const char* Items_SingleStringGetter(void* data, int idx)
|
||||
{
|
||||
if (idx == items_count)
|
||||
break;
|
||||
p += strlen(p) + 1;
|
||||
p += ImStrlen(p) + 1;
|
||||
items_count++;
|
||||
}
|
||||
return *p ? p : NULL;
|
||||
@@ -2060,7 +2083,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char* (*getter)(vo
|
||||
preview_value = getter(user_data, *current_item);
|
||||
|
||||
// The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here.
|
||||
if (popup_max_height_in_items != -1 && !(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint))
|
||||
if (popup_max_height_in_items != -1 && !(g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSizeConstraint))
|
||||
SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items)));
|
||||
|
||||
if (!BeginCombo(label, preview_value, ImGuiComboFlags_None))
|
||||
@@ -2111,7 +2134,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char* items_separa
|
||||
const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open
|
||||
while (*p)
|
||||
{
|
||||
p += strlen(p) + 1;
|
||||
p += ImStrlen(p) + 1;
|
||||
items_count++;
|
||||
}
|
||||
bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items);
|
||||
@@ -2621,7 +2644,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
|
||||
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
|
||||
if (!temp_input_is_active)
|
||||
{
|
||||
// Tabbing or CTRL-clicking on Drag turns it into an InputText
|
||||
// Tabbing or CTRL+click on Drag turns it into an InputText
|
||||
const bool clicked = hovered && IsMouseClicked(0, ImGuiInputFlags_None, id);
|
||||
const bool double_clicked = (hovered && g.IO.MouseClickedCount[0] == 2 && TestKeyOwner(ImGuiKey_MouseLeft, id));
|
||||
const bool make_active = (clicked || double_clicked || g.NavActivateId == id);
|
||||
@@ -3225,7 +3248,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
|
||||
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
|
||||
if (!temp_input_is_active)
|
||||
{
|
||||
// Tabbing or CTRL-clicking on Slider turns it into an input box
|
||||
// Tabbing or CTRL+click on Slider turns it into an input box
|
||||
const bool clicked = hovered && IsMouseClicked(0, ImGuiInputFlags_None, id);
|
||||
const bool make_active = (clicked || g.NavActivateId == id);
|
||||
if (make_active && clicked)
|
||||
@@ -3878,7 +3901,7 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char**
|
||||
line_count++;
|
||||
if (s_eol == NULL)
|
||||
{
|
||||
s = s + strlen(s);
|
||||
s = s + ImStrlen(s);
|
||||
break;
|
||||
}
|
||||
s = s_eol + 1;
|
||||
@@ -4166,7 +4189,7 @@ void ImGuiInputTextState::OnCharPressed(unsigned int c)
|
||||
// The changes we had to make to stb_textedit_key made it very much UTF-8 specific which is not too great.
|
||||
char utf8[5];
|
||||
ImTextCharToUtf8(utf8, c);
|
||||
stb_textedit_text(this, Stb, utf8, (int)strlen(utf8));
|
||||
stb_textedit_text(this, Stb, utf8, (int)ImStrlen(utf8));
|
||||
CursorFollow = true;
|
||||
CursorAnimReset();
|
||||
}
|
||||
@@ -4217,7 +4240,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
|
||||
|
||||
// Grow internal buffer if needed
|
||||
const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0;
|
||||
const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);
|
||||
const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)ImStrlen(new_text);
|
||||
if (new_text_len + BufTextLen >= BufSize)
|
||||
{
|
||||
if (!is_resizable)
|
||||
@@ -4251,7 +4274,7 @@ void ImGui::PushPasswordFont()
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImFont* in_font = g.Font;
|
||||
ImFont* out_font = &g.InputTextPasswordFont;
|
||||
const ImFontGlyph* glyph = in_font->FindGlyph('*');
|
||||
ImFontGlyph* glyph = in_font->FindGlyph('*');
|
||||
out_font->FontSize = in_font->FontSize;
|
||||
out_font->Scale = in_font->Scale;
|
||||
out_font->Ascent = in_font->Ascent;
|
||||
@@ -4273,7 +4296,13 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im
|
||||
if (c < 0x20)
|
||||
{
|
||||
bool pass = false;
|
||||
pass |= (c == '\n') && (flags & ImGuiInputTextFlags_Multiline) != 0; // Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code)
|
||||
pass |= (c == '\n') && (flags & ImGuiInputTextFlags_Multiline) != 0; // Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code)
|
||||
if (c == '\n' && input_source_is_clipboard && (flags & ImGuiInputTextFlags_Multiline) == 0) // In single line mode, replace \n with a space
|
||||
{
|
||||
c = *p_char = ' ';
|
||||
pass = true;
|
||||
}
|
||||
pass |= (c == '\n') && (flags & ImGuiInputTextFlags_Multiline) != 0;
|
||||
pass |= (c == '\t') && (flags & ImGuiInputTextFlags_AllowTabInput) != 0;
|
||||
if (!pass)
|
||||
return false;
|
||||
@@ -4539,7 +4568,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
const bool init_state = (init_make_active || user_scroll_active);
|
||||
if (init_reload_from_user_buf)
|
||||
{
|
||||
int new_len = (int)strlen(buf);
|
||||
int new_len = (int)ImStrlen(buf);
|
||||
IM_ASSERT(new_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?");
|
||||
state->WantReloadUserBuf = false;
|
||||
InputTextReconcileUndoState(state, state->TextA.Data, state->TextLen, buf, new_len);
|
||||
@@ -4561,7 +4590,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
// Take a copy of the initial buffer value.
|
||||
// From the moment we focused we are normally ignoring the content of 'buf' (unless we are in read-only mode)
|
||||
const int buf_len = (int)strlen(buf);
|
||||
const int buf_len = (int)ImStrlen(buf);
|
||||
IM_ASSERT(buf_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?");
|
||||
state->TextToRevertTo.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string.
|
||||
memcpy(state->TextToRevertTo.Data, buf, buf_len + 1);
|
||||
@@ -4646,7 +4675,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
// Read-only mode always ever read from source buffer. Refresh TextLen when active.
|
||||
if (is_readonly && state != NULL)
|
||||
state->TextLen = (int)strlen(buf);
|
||||
state->TextLen = (int)ImStrlen(buf);
|
||||
//if (is_readonly && state != NULL)
|
||||
// state->TextA.clear(); // Uncomment to facilitate debugging, but we otherwise prefer to keep/amortize th allocation.
|
||||
}
|
||||
@@ -4669,7 +4698,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
// Select the buffer to render.
|
||||
const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state;
|
||||
const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
|
||||
bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
|
||||
|
||||
// Password pushes a temporary font with only a fallback glyph
|
||||
if (is_password && !is_displaying_hint)
|
||||
@@ -4803,14 +4832,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl
|
||||
const bool is_startend_key_down = is_osx && io.KeyCtrl && !io.KeySuper && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
|
||||
|
||||
// Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: formet would be handled by InputText)
|
||||
// Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: former would be handled by InputText)
|
||||
// Otherwise we could simply assume that we own the keys as we are active.
|
||||
const ImGuiInputFlags f_repeat = ImGuiInputFlags_Repeat;
|
||||
const bool is_cut = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_X, f_repeat, id) || Shortcut(ImGuiMod_Shift | ImGuiKey_Delete, f_repeat, id)) && !is_readonly && !is_password && (!is_multiline || state->HasSelection());
|
||||
const bool is_copy = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_C, 0, id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_Insert, 0, id)) && !is_password && (!is_multiline || state->HasSelection());
|
||||
const bool is_paste = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_V, f_repeat, id) || Shortcut(ImGuiMod_Shift | ImGuiKey_Insert, f_repeat, id)) && !is_readonly;
|
||||
const bool is_undo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Z, f_repeat, id)) && !is_readonly && is_undoable;
|
||||
const bool is_redo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Y, f_repeat, id) || (is_osx && Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Z, f_repeat, id))) && !is_readonly && is_undoable;
|
||||
const bool is_redo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Y, f_repeat, id) || Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Z, f_repeat, id)) && !is_readonly && is_undoable;
|
||||
const bool is_select_all = Shortcut(ImGuiMod_Ctrl | ImGuiKey_A, 0, id);
|
||||
|
||||
// We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful.
|
||||
@@ -4925,7 +4954,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
if (const char* clipboard = GetClipboardText())
|
||||
{
|
||||
// Filter pasted buffer
|
||||
const int clipboard_len = (int)strlen(clipboard);
|
||||
const int clipboard_len = (int)ImStrlen(clipboard);
|
||||
ImVector<char> clipboard_filtered;
|
||||
clipboard_filtered.reserve(clipboard_len + 1);
|
||||
for (const char* s = clipboard; *s != 0; )
|
||||
@@ -4937,7 +4966,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
continue;
|
||||
char c_utf8[5];
|
||||
ImTextCharToUtf8(c_utf8, c);
|
||||
int out_len = (int)strlen(c_utf8);
|
||||
int out_len = (int)ImStrlen(c_utf8);
|
||||
clipboard_filtered.resize(clipboard_filtered.Size + out_len);
|
||||
memcpy(clipboard_filtered.Data + clipboard_filtered.Size - out_len, c_utf8, out_len);
|
||||
}
|
||||
@@ -5067,7 +5096,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
if (buf_dirty)
|
||||
{
|
||||
// Callback may update buffer and thus set buf_dirty even in read-only mode.
|
||||
IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
|
||||
IM_ASSERT(callback_data.BufTextLen == (int)ImStrlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
|
||||
InputTextReconcileUndoState(state, state->CallbackTextBackup.Data, state->CallbackTextBackup.Size - 1, callback_data.Buf, callback_data.BufTextLen);
|
||||
state->TextLen = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
|
||||
state->CursorAnimReset();
|
||||
@@ -5151,10 +5180,22 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
const int buf_display_max_length = 2 * 1024 * 1024;
|
||||
const char* buf_display = buf_display_from_state ? state->TextA.Data : buf; //-V595
|
||||
const char* buf_display_end = NULL; // We have specialized paths below for setting the length
|
||||
|
||||
// Display hint when contents is empty
|
||||
// At this point we need to handle the possibility that a callback could have modified the underlying buffer (#8368)
|
||||
const bool new_is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
|
||||
if (new_is_displaying_hint != is_displaying_hint)
|
||||
{
|
||||
if (is_password && !is_displaying_hint)
|
||||
PopFont();
|
||||
is_displaying_hint = new_is_displaying_hint;
|
||||
if (is_password && !is_displaying_hint)
|
||||
PushPasswordFont();
|
||||
}
|
||||
if (is_displaying_hint)
|
||||
{
|
||||
buf_display = hint;
|
||||
buf_display_end = hint + strlen(hint);
|
||||
buf_display_end = hint + ImStrlen(hint);
|
||||
}
|
||||
|
||||
// Render text. We currently only render selection when the widget is active or while scrolling.
|
||||
@@ -5187,7 +5228,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
int line_count = 1;
|
||||
if (is_multiline)
|
||||
{
|
||||
for (const char* s = text_begin; (s = (const char*)memchr(s, '\n', (size_t)(text_end - s))) != NULL; s++)
|
||||
for (const char* s = text_begin; (s = (const char*)ImMemchr(s, '\n', (size_t)(text_end - s))) != NULL; s++)
|
||||
{
|
||||
if (cursor_line_no == -1 && s >= cursor_ptr) { cursor_line_no = line_count; }
|
||||
if (selmin_line_no == -1 && s >= selmin_ptr) { selmin_line_no = line_count; }
|
||||
@@ -5265,7 +5306,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
break;
|
||||
if (rect_pos.y < clip_rect.y)
|
||||
{
|
||||
p = (const char*)memchr((void*)p, '\n', text_selected_end - p);
|
||||
p = (const char*)ImMemchr((void*)p, '\n', text_selected_end - p);
|
||||
p = p ? p + 1 : text_selected_end;
|
||||
}
|
||||
else
|
||||
@@ -5317,7 +5358,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
else if (!is_displaying_hint && g.ActiveId == id)
|
||||
buf_display_end = buf_display + state->TextLen;
|
||||
else if (!is_displaying_hint)
|
||||
buf_display_end = buf_display + strlen(buf_display);
|
||||
buf_display_end = buf_display + ImStrlen(buf_display);
|
||||
|
||||
if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)
|
||||
{
|
||||
@@ -5462,7 +5503,7 @@ static void ColorEditRestoreHS(const float* col, float* H, float* S, float* V)
|
||||
|
||||
// Edit colors components (each component in 0.0f..1.0f range).
|
||||
// See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
|
||||
// With typical options: Left-click on color square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item.
|
||||
// With typical options: Left-click on color square to open color picker. Right-click to open option menu. CTRL+Click over input fields to edit them and TAB to go to next item.
|
||||
bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
@@ -6166,7 +6207,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
|
||||
if (g.Style.FrameBorderSize > 0.0f)
|
||||
RenderFrameBorder(bb.Min, bb.Max, rounding);
|
||||
else
|
||||
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border
|
||||
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color buttons are often in need of some sort of border
|
||||
}
|
||||
|
||||
// Drag and Drop Source
|
||||
@@ -7088,7 +7129,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||
|
||||
// Text stays at the submission position. Alignment/clipping extents ignore SpanAllColumns.
|
||||
if (is_visible)
|
||||
RenderTextClipped(pos, ImVec2(window->WorkRect.Max.x, pos.y + size.y), label, NULL, &label_size, style.SelectableTextAlign, &bb);
|
||||
RenderTextClipped(pos, ImVec2(ImMin(pos.x + size.x, 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))
|
||||
@@ -7151,7 +7192,7 @@ ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags f
|
||||
|
||||
// Append to buffer
|
||||
const int buffer_max_len = IM_ARRAYSIZE(data->SearchBuffer) - 1;
|
||||
int buffer_len = (int)strlen(data->SearchBuffer);
|
||||
int buffer_len = (int)ImStrlen(data->SearchBuffer);
|
||||
bool select_request = false;
|
||||
for (ImWchar w : g.IO.InputQueueCharacters)
|
||||
{
|
||||
@@ -8834,7 +8875,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
||||
if (g.MenusIdSubmittedThisFrame.contains(id))
|
||||
{
|
||||
if (menu_is_open)
|
||||
menu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
|
||||
menu_is_open = BeginPopupMenuEx(id, label, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
|
||||
else
|
||||
g.NextWindowData.ClearFlags(); // we behave like Begin() and need to consume those values
|
||||
return menu_is_open;
|
||||
@@ -8865,7 +8906,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
||||
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_NoAutoClosePopups;
|
||||
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
|
||||
{
|
||||
// Menu inside an horizontal menu bar
|
||||
// Menu inside a horizontal menu bar
|
||||
// Selectable extend their highlight by half ItemSpacing in each direction.
|
||||
// For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin()
|
||||
popup_pos = ImVec2(pos.x - 1.0f - IM_TRUNC(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight);
|
||||
@@ -8996,7 +9037,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
||||
ImGuiLastItemData last_item_in_parent = g.LastItemData;
|
||||
SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: misleading: the value will serve as reference for FindBestWindowPosForPopup(), not actual pos.
|
||||
PushStyleVar(ImGuiStyleVar_ChildRounding, style.PopupRounding); // First level will use _PopupRounding, subsequent will use _ChildRounding
|
||||
menu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
|
||||
menu_is_open = BeginPopupMenuEx(id, label, window_flags); // menu_is_open may be 'false' when the popup is completely clipped (e.g. zero size display)
|
||||
PopStyleVar();
|
||||
if (menu_is_open)
|
||||
{
|
||||
@@ -10078,7 +10119,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
else
|
||||
{
|
||||
tab->NameOffset = (ImS32)tab_bar->TabsNames.size();
|
||||
tab_bar->TabsNames.append(label, label + strlen(label) + 1);
|
||||
tab_bar->TabsNames.append(label, label + ImStrlen(label) + 1);
|
||||
}
|
||||
|
||||
// Update selected tab
|
||||
@@ -10355,13 +10396,24 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
|
||||
// 'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered booleans are false
|
||||
bool close_button_pressed = false;
|
||||
bool close_button_visible = false;
|
||||
if (close_button_id != 0)
|
||||
if (is_contents_visible || bb.GetWidth() >= ImMax(button_sz, g.Style.TabMinWidthForCloseButton))
|
||||
if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id)
|
||||
close_button_visible = true;
|
||||
bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x);
|
||||
bool is_hovered = g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id; // Any interaction account for this too.
|
||||
|
||||
if (close_button_visible)
|
||||
if (close_button_id != 0)
|
||||
{
|
||||
if (is_contents_visible)
|
||||
close_button_visible = (g.Style.TabCloseButtonMinWidthSelected < 0.0f) ? true : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthSelected));
|
||||
else
|
||||
close_button_visible = (g.Style.TabCloseButtonMinWidthUnselected < 0.0f) ? true : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthUnselected));
|
||||
}
|
||||
|
||||
// When tabs/document is unsaved, the unsaved marker takes priority over the close button.
|
||||
const bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x) && (!close_button_visible || !is_hovered);
|
||||
if (unsaved_marker_visible)
|
||||
{
|
||||
const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz));
|
||||
RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text));
|
||||
}
|
||||
else if (close_button_visible)
|
||||
{
|
||||
ImGuiLastItemData last_item_backup = g.LastItemData;
|
||||
if (CloseButton(close_button_id, button_pos))
|
||||
@@ -10369,14 +10421,9 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
|
||||
g.LastItemData = last_item_backup;
|
||||
|
||||
// Close with middle mouse button
|
||||
if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2))
|
||||
if (is_hovered && !(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2))
|
||||
close_button_pressed = true;
|
||||
}
|
||||
else if (unsaved_marker_visible)
|
||||
{
|
||||
const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz));
|
||||
RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text));
|
||||
}
|
||||
|
||||
// This is all rather complicated
|
||||
// (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position)
|
||||
|
||||
@@ -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
@@ -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,6 +637,7 @@
|
||||
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,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,
|
||||
@@ -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,
|
||||
@@ -1070,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,
|
||||
@@ -1244,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,
|
||||
@@ -1380,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,
|
||||
@@ -1441,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,
|
||||
@@ -1497,11 +1502,11 @@ 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,
|
||||
030000006f0e0000f102000000000000,PDP Xbox Atomic,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,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,
|
||||
@@ -1520,6 +1525,7 @@ 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,
|
||||
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,
|
||||
@@ -1611,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,
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 91 KiB |
@@ -25,7 +25,8 @@
|
||||
#define SW_AD_TO_HW (PS_BLEND_C == 1 && PS_A_MASKED)
|
||||
#define PS_PRIMID_INIT (PS_DATE == 1 || PS_DATE == 2)
|
||||
#define NEEDS_RT_EARLY (PS_TEX_IS_FB == 1 || PS_DATE >= 5)
|
||||
#define NEEDS_RT (NEEDS_RT_EARLY || (!PS_PRIMID_INIT && (PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW)))
|
||||
#define NEEDS_RT_FOR_AFAIL (PS_AFAIL == 3 && PS_NO_COLOR1)
|
||||
#define NEEDS_RT (NEEDS_RT_EARLY || NEEDS_RT_FOR_AFAIL || (!PS_PRIMID_INIT && (PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW)))
|
||||
#define NEEDS_TEX (PS_TFX != 4)
|
||||
|
||||
layout(std140, binding = 0) uniform cb21
|
||||
@@ -111,7 +112,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 +128,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 +313,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 +322,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 +698,6 @@ vec4 ps_color()
|
||||
|
||||
vec4 C = tfx(T, PSin.c);
|
||||
|
||||
atst(C);
|
||||
|
||||
fog(C, PSin.t_float.z);
|
||||
|
||||
return C;
|
||||
@@ -709,9 +708,9 @@ void ps_fbmask(inout vec4 C)
|
||||
// FIXME do I need special case for 16 bits
|
||||
#if PS_FBMASK
|
||||
#if PS_HDR == 1
|
||||
vec4 RT = trunc(fetch_rt() * 65535.0f);
|
||||
vec4 RT = trunc(sample_from_rt() * 65535.0f);
|
||||
#else
|
||||
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
#endif
|
||||
C = vec4((uvec4(C) & ~FbMask) | (uvec4(RT) & FbMask));
|
||||
#endif
|
||||
@@ -799,7 +798,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);
|
||||
@@ -974,9 +973,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
|
||||
@@ -1028,9 +1027,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);
|
||||
@@ -1116,7 +1115,7 @@ void ps_main()
|
||||
|
||||
ps_fbmask(C);
|
||||
|
||||
#if PS_AFAIL == 3 // RGB_ONLY
|
||||
#if PS_AFAIL == 3 && !PS_NO_COLOR1 // RGB_ONLY
|
||||
// Use alpha blend factor to determine whether to update A.
|
||||
alpha_blend.a = float(atst_pass);
|
||||
#endif
|
||||
@@ -1132,6 +1131,10 @@ void ps_main()
|
||||
#else
|
||||
SV_Target0.rgb = C.rgb / 255.0f;
|
||||
#endif
|
||||
#if PS_AFAIL == 3 && !PS_NO_COLOR1 // RGB_ONLY, no dual src blend
|
||||
if (!atst_pass)
|
||||
SV_Target0.a = sample_from_rt().a;
|
||||
#endif
|
||||
#if !PS_NO_COLOR1
|
||||
SV_Target1 = alpha_blend;
|
||||
#endif
|
||||
|
||||
@@ -299,8 +299,9 @@ void main()
|
||||
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
|
||||
#define SW_BLEND_NEEDS_RT (SW_BLEND && (PS_BLEND_A == 1 || PS_BLEND_B == 1 || PS_BLEND_C == 1 || PS_BLEND_D == 1))
|
||||
#define SW_AD_TO_HW (PS_BLEND_C == 1 && PS_A_MASKED)
|
||||
#define AFAIL_NEEDS_RT (PS_AFAIL == 3 && PS_NO_COLOR1)
|
||||
|
||||
#define PS_FEEDBACK_LOOP_IS_NEEDED (PS_TEX_IS_FB == 1 || PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW || (PS_DATE >= 5))
|
||||
#define PS_FEEDBACK_LOOP_IS_NEEDED (PS_TEX_IS_FB == 1 || AFAIL_NEEDS_RT || PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW || (PS_DATE >= 5))
|
||||
|
||||
#define NEEDS_TEX (PS_TFX != 4)
|
||||
|
||||
@@ -954,7 +955,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
|
||||
@@ -1381,7 +1382,7 @@ void main()
|
||||
|
||||
ps_fbmask(C);
|
||||
|
||||
#if PS_AFAIL == 3 // RGB_ONLY
|
||||
#if PS_AFAIL == 3 && !PS_NO_COLOR1 // RGB_ONLY
|
||||
// Use alpha blend factor to determine whether to update A.
|
||||
alpha_blend.a = float(atst_pass);
|
||||
#endif
|
||||
@@ -1400,6 +1401,10 @@ void main()
|
||||
#if !PS_NO_COLOR1
|
||||
o_col1 = alpha_blend;
|
||||
#endif
|
||||
#if PS_AFAIL == 3 && PS_NO_COLOR1 // RGB_ONLY, no dual src blend
|
||||
if (!atst_pass)
|
||||
o_col0.a = sample_from_rt().a;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PS_ZCLAMP
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -113,6 +113,10 @@ bool GSRunner::InitializeConfig()
|
||||
si.SetBoolValue("EmuCore/GS", "FrameLimitEnable", false);
|
||||
si.SetIntValue("EmuCore/GS", "VsyncEnable", false);
|
||||
|
||||
// Force screenshot quality settings to something more performant, overriding any defaults good for users.
|
||||
si.SetIntValue("EmuCore/GS", "ScreenshotFormat", static_cast<int>(GSScreenshotFormat::PNG));
|
||||
si.SetIntValue("EmuCore/GS", "ScreenshotQuality", 10);
|
||||
|
||||
// ensure all input sources are disabled, we're not using them
|
||||
si.SetBoolValue("InputSources", "SDL", false);
|
||||
si.SetBoolValue("InputSources", "XInput", false);
|
||||
@@ -169,11 +173,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 +264,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 +461,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 +492,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 +513,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 +528,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 +651,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 +764,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())
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
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;
|
||||
const 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));
|
||||
@@ -374,9 +401,14 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
|
||||
bool BreakpointModel::removeRows(int row, int count, const QModelIndex& index)
|
||||
{
|
||||
const size_t begin_index = static_cast<size_t>(row);
|
||||
const size_t end_index = static_cast<size_t>(row + count);
|
||||
if (end_index > m_breakpoints.size())
|
||||
return false;
|
||||
|
||||
beginRemoveRows(index, row, row + count - 1);
|
||||
|
||||
for (int i = row; i < row + count; i++)
|
||||
for (size_t i = begin_index; i < end_index; i++)
|
||||
{
|
||||
auto bp_mc = m_breakpoints.at(i);
|
||||
|
||||
@@ -393,6 +425,7 @@ bool BreakpointModel::removeRows(int row, int count, const QModelIndex& index)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const auto begin = m_breakpoints.begin() + row;
|
||||
const auto end = begin + count;
|
||||
m_breakpoints.erase(begin, end);
|
||||
@@ -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;
|
||||
};
|
||||
174
pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.cpp
Normal file
174
pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
// 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 indices = selModel->selectedIndexes();
|
||||
|
||||
std::set<int> rows;
|
||||
for (QModelIndex index : indices)
|
||||
rows.emplace(index.row());
|
||||
|
||||
for (auto row = rows.rbegin(); row != rows.rend(); row++)
|
||||
m_model->removeRows(*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();
|
||||
};
|
||||
107
pcsx2-qt/Debugger/Docking/LayoutEditorDialog.cpp
Normal file
107
pcsx2-qt/Debugger/Docking/LayoutEditorDialog.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "LayoutEditorDialog.h"
|
||||
|
||||
#include "Debugger/Docking/DockTables.h"
|
||||
|
||||
#include <QtWidgets/QPushButton>
|
||||
|
||||
Q_DECLARE_METATYPE(LayoutEditorDialog::InitialState);
|
||||
|
||||
LayoutEditorDialog::LayoutEditorDialog(NameValidator name_validator, bool can_clone_current_layout, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_name_validator(name_validator)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
setWindowTitle(tr("New Layout"));
|
||||
|
||||
setupInputWidgets(BREAKPOINT_EE, can_clone_current_layout);
|
||||
|
||||
onNameChanged();
|
||||
}
|
||||
|
||||
LayoutEditorDialog::LayoutEditorDialog(
|
||||
const QString& name, BreakPointCpu cpu, NameValidator name_validator, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_name_validator(name_validator)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
setWindowTitle(tr("Edit Layout"));
|
||||
|
||||
m_ui.nameEditor->setText(name);
|
||||
|
||||
setupInputWidgets(cpu, {});
|
||||
|
||||
m_ui.initialStateLabel->hide();
|
||||
m_ui.initialStateEditor->hide();
|
||||
|
||||
onNameChanged();
|
||||
}
|
||||
|
||||
QString LayoutEditorDialog::name()
|
||||
{
|
||||
return m_ui.nameEditor->text();
|
||||
}
|
||||
|
||||
BreakPointCpu LayoutEditorDialog::cpu()
|
||||
{
|
||||
return static_cast<BreakPointCpu>(m_ui.cpuEditor->currentData().toInt());
|
||||
}
|
||||
|
||||
LayoutEditorDialog::InitialState LayoutEditorDialog::initialState()
|
||||
{
|
||||
return m_ui.initialStateEditor->currentData().value<InitialState>();
|
||||
}
|
||||
|
||||
void LayoutEditorDialog::setupInputWidgets(BreakPointCpu cpu, bool can_clone_current_layout)
|
||||
{
|
||||
connect(m_ui.nameEditor, &QLineEdit::textChanged, this, &LayoutEditorDialog::onNameChanged);
|
||||
|
||||
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);
|
||||
m_ui.cpuEditor->addItem(text, cpu);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_ui.cpuEditor->count(); i++)
|
||||
if (m_ui.cpuEditor->itemData(i).toInt() == cpu)
|
||||
m_ui.cpuEditor->setCurrentIndex(i);
|
||||
|
||||
for (size_t i = 0; i < DockTables::DEFAULT_DOCK_LAYOUTS.size(); i++)
|
||||
m_ui.initialStateEditor->addItem(
|
||||
tr("Create Default \"%1\" Layout").arg(tr(DockTables::DEFAULT_DOCK_LAYOUTS[i].name.c_str())),
|
||||
QVariant::fromValue(InitialState(DEFAULT_LAYOUT, i)));
|
||||
|
||||
m_ui.initialStateEditor->addItem(tr("Create Blank Layout"), QVariant::fromValue(InitialState(BLANK_LAYOUT, 0)));
|
||||
|
||||
if (can_clone_current_layout)
|
||||
m_ui.initialStateEditor->addItem(tr("Clone Current Layout"), QVariant::fromValue(InitialState(CLONE_LAYOUT, 0)));
|
||||
|
||||
m_ui.initialStateEditor->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
void LayoutEditorDialog::onNameChanged()
|
||||
{
|
||||
QString error_message;
|
||||
|
||||
if (m_ui.nameEditor->text().isEmpty())
|
||||
{
|
||||
error_message = tr("Name is empty.");
|
||||
}
|
||||
else if (m_ui.nameEditor->text().size() > DockUtils::MAX_LAYOUT_NAME_SIZE)
|
||||
{
|
||||
error_message = tr("Name too long.");
|
||||
}
|
||||
else if (!m_name_validator(m_ui.nameEditor->text()))
|
||||
{
|
||||
error_message = tr("A layout with that name already exists.");
|
||||
}
|
||||
|
||||
m_ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(error_message.isEmpty());
|
||||
m_ui.errorMessage->setText(error_message);
|
||||
}
|
||||
45
pcsx2-qt/Debugger/Docking/LayoutEditorDialog.h
Normal file
45
pcsx2-qt/Debugger/Docking/LayoutEditorDialog.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_LayoutEditorDialog.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
#include <QtWidgets/QDialog>
|
||||
|
||||
class LayoutEditorDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using NameValidator = std::function<bool(const QString&)>;
|
||||
|
||||
enum CreationMode
|
||||
{
|
||||
DEFAULT_LAYOUT,
|
||||
BLANK_LAYOUT,
|
||||
CLONE_LAYOUT,
|
||||
};
|
||||
|
||||
// Bundles together a creation mode and inital state.
|
||||
using InitialState = std::pair<CreationMode, size_t>;
|
||||
|
||||
// Create a "New Layout" dialog.
|
||||
LayoutEditorDialog(NameValidator name_validator, bool can_clone_current_layout, QWidget* parent = nullptr);
|
||||
|
||||
// Create a "Edit Layout" dialog.
|
||||
LayoutEditorDialog(const QString& name, BreakPointCpu cpu, NameValidator name_validator, QWidget* parent = nullptr);
|
||||
|
||||
QString name();
|
||||
BreakPointCpu cpu();
|
||||
InitialState initialState();
|
||||
|
||||
private:
|
||||
void setupInputWidgets(BreakPointCpu cpu, bool can_clone_current_layout);
|
||||
void onNameChanged();
|
||||
|
||||
Ui::LayoutEditorDialog m_ui;
|
||||
NameValidator m_name_validator;
|
||||
};
|
||||
115
pcsx2-qt/Debugger/Docking/LayoutEditorDialog.ui
Normal file
115
pcsx2-qt/Debugger/Docking/LayoutEditorDialog.ui
Normal file
@@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LayoutEditorDialog</class>
|
||||
<widget class="QDialog" name="LayoutEditorDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>150</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="nameLabel">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="cpuLabel">
|
||||
<property name="text">
|
||||
<string>Target</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="initialStateLabel">
|
||||
<property name="text">
|
||||
<string>Initial State</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="cpuEditor"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="nameEditor"/>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="initialStateEditor"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="errorMessage">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: red</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>LayoutEditorDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>LayoutEditorDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
15
pcsx2-qt/Debugger/Docking/NoLayoutsWidget.cpp
Normal file
15
pcsx2-qt/Debugger/Docking/NoLayoutsWidget.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "NoLayoutsWidget.h"
|
||||
|
||||
NoLayoutsWidget::NoLayoutsWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
}
|
||||
|
||||
QPushButton* NoLayoutsWidget::createDefaultLayoutsButton()
|
||||
{
|
||||
return m_ui.createDefaultLayoutsButton;
|
||||
}
|
||||
21
pcsx2-qt/Debugger/Docking/NoLayoutsWidget.h
Normal file
21
pcsx2-qt/Debugger/Docking/NoLayoutsWidget.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_NoLayoutsWidget.h"
|
||||
|
||||
#include <QtWidgets/QPushButton>
|
||||
|
||||
class NoLayoutsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NoLayoutsWidget(QWidget* parent = nullptr);
|
||||
|
||||
QPushButton* createDefaultLayoutsButton();
|
||||
|
||||
private:
|
||||
Ui::NoLayoutsWidget m_ui;
|
||||
};
|
||||
97
pcsx2-qt/Debugger/Docking/NoLayoutsWidget.ui
Normal file
97
pcsx2-qt/Debugger/Docking/NoLayoutsWidget.ui
Normal file
@@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>NoLayoutsWidget</class>
|
||||
<widget class="QWidget" name="NoLayoutsWidget">
|
||||
<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>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<spacer name="topSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>There are no layouts.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="leftSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="createDefaultLayoutsButton">
|
||||
<property name="text">
|
||||
<string>Create Default Layouts</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="rightSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="bottomSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user