mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 15:57:03 -05:00
Compare commits
203 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69973af1ed | ||
|
|
f0c679fb61 | ||
|
|
5a2e2b1773 | ||
|
|
e720b61df6 | ||
|
|
44b121e8b0 | ||
|
|
6a7c086514 | ||
|
|
3b59868f62 | ||
|
|
0b77a3f2c1 | ||
|
|
957dfeed81 | ||
|
|
451c550b19 | ||
|
|
21cc8555b5 | ||
|
|
19b80a1c2d | ||
|
|
a000b1a2fe | ||
|
|
856055a04d | ||
|
|
be1c5f5d1d | ||
|
|
278d46ccd7 | ||
|
|
0da31b6bbb | ||
|
|
e8bc94a25a | ||
|
|
d12869dbac | ||
|
|
fecd70c9ad | ||
|
|
4effa999b3 | ||
|
|
dd35a717b7 | ||
|
|
c71577b7bf | ||
|
|
1d3736b98c | ||
|
|
efad16f2c0 | ||
|
|
243820ca95 | ||
|
|
28805bae65 | ||
|
|
e074643783 | ||
|
|
9340c8aae3 | ||
|
|
9158d79126 | ||
|
|
ded452fdfc | ||
|
|
467e9d1463 | ||
|
|
1429f80cf9 | ||
|
|
372908ba9d | ||
|
|
0d1686e170 | ||
|
|
aa527ba29b | ||
|
|
9a545a48ab | ||
|
|
9e808f3ecd | ||
|
|
cb583b5d6c | ||
|
|
2e3c43ad9e | ||
|
|
594a6c1c0f | ||
|
|
15f81cc316 | ||
|
|
434de44ef5 | ||
|
|
1c1396bf4b | ||
|
|
beea4c4147 | ||
|
|
849f6aa3d9 | ||
|
|
3c4d57f63b | ||
|
|
116caeaa74 | ||
|
|
673d43b526 | ||
|
|
c88053a575 | ||
|
|
1f250e87a3 | ||
|
|
cd89b55f5b | ||
|
|
716d6573ca | ||
|
|
a6b8597f5a | ||
|
|
cab1089e22 | ||
|
|
c95e12c136 | ||
|
|
d9a77d396c | ||
|
|
442f164159 | ||
|
|
d6f9ec3f8f | ||
|
|
9ccfadfb54 | ||
|
|
8b6de30e92 | ||
|
|
6408741733 | ||
|
|
7562e8b172 | ||
|
|
929437c159 | ||
|
|
93474d7f43 | ||
|
|
58e3031510 | ||
|
|
1b66c84303 | ||
|
|
1c321b7de2 | ||
|
|
e3cf364903 | ||
|
|
9b1c09818c | ||
|
|
46ba46ce9d | ||
|
|
1b6035d6c6 | ||
|
|
3e5d6cf88c | ||
|
|
a4c5d0bb62 | ||
|
|
9b316795fc | ||
|
|
b12cd66679 | ||
|
|
aac1a37a3f | ||
|
|
140234aef3 | ||
|
|
ec9715f326 | ||
|
|
69ca14bf46 | ||
|
|
0226f3d047 | ||
|
|
76391edad6 | ||
|
|
9b3822a8bd | ||
|
|
72ec6baf79 | ||
|
|
21769886fc | ||
|
|
2dc1886ee9 | ||
|
|
a29e3789d2 | ||
|
|
17db605b17 | ||
|
|
4e520938c9 | ||
|
|
7498a72f70 | ||
|
|
241bbd80bc | ||
|
|
2e05845410 | ||
|
|
a67263fa27 | ||
|
|
6d8b7bef09 | ||
|
|
3e30f75e7b | ||
|
|
7eb4b40dc7 | ||
|
|
e3a6ac548b | ||
|
|
044e65eb20 | ||
|
|
545604da63 | ||
|
|
4b9aff5b29 | ||
|
|
a93049056a | ||
|
|
3543fa4caa | ||
|
|
51a98736e8 | ||
|
|
12a8cadcfe | ||
|
|
aef959854f | ||
|
|
066161f397 | ||
|
|
d3e3de3fa2 | ||
|
|
194bc3e5be | ||
|
|
a9e3db0464 | ||
|
|
334ba3ede2 | ||
|
|
7978964995 | ||
|
|
d5ca4c4f28 | ||
|
|
08c2e1cd4e | ||
|
|
2f6e91cd9e | ||
|
|
888976873a | ||
|
|
5db608c3fc | ||
|
|
e46807c600 | ||
|
|
7799bbb57a | ||
|
|
7da8a5b1d8 | ||
|
|
ae9f4fa876 | ||
|
|
e3dd5900e2 | ||
|
|
aab865fe25 | ||
|
|
62656f4c51 | ||
|
|
b323d711cf | ||
|
|
9b4cf917d9 | ||
|
|
ba97573f93 | ||
|
|
9dc62e1469 | ||
|
|
55c0cb66e3 | ||
|
|
a8526585cb | ||
|
|
3850349eae | ||
|
|
f5bd0b7971 | ||
|
|
42d9753bdb | ||
|
|
17d5a5309a | ||
|
|
71be77c54b | ||
|
|
93c1fbd65e | ||
|
|
c8114347dc | ||
|
|
3c2c2b003f | ||
|
|
2edd6cd6c4 | ||
|
|
6713f65040 | ||
|
|
82ee4ad4ca | ||
|
|
d9134f7fe1 | ||
|
|
ee26839292 | ||
|
|
cd33376c07 | ||
|
|
e57481b87c | ||
|
|
5601aab043 | ||
|
|
1b7a1852bc | ||
|
|
509795e6c1 | ||
|
|
755642862f | ||
|
|
d1c05174b6 | ||
|
|
85b8698e35 | ||
|
|
471ba80b4d | ||
|
|
9dd555f111 | ||
|
|
7df1ff07a7 | ||
|
|
15a60930d2 | ||
|
|
eb779c5986 | ||
|
|
c051f5d3e7 | ||
|
|
ed9e463550 | ||
|
|
a7ebf1f60e | ||
|
|
6ab0ec547c | ||
|
|
26a0352851 | ||
|
|
8631cb0c2a | ||
|
|
a302448b76 | ||
|
|
fef072f721 | ||
|
|
46f196cb3f | ||
|
|
c5cd6422c6 | ||
|
|
5edc0b876c | ||
|
|
131699d309 | ||
|
|
59c01feaea | ||
|
|
772b50fdfb | ||
|
|
bf493c5763 | ||
|
|
e1f410ceff | ||
|
|
d3fb00d441 | ||
|
|
222e9f6645 | ||
|
|
22a904baf4 | ||
|
|
01670e5e85 | ||
|
|
7fbb540674 | ||
|
|
bed5361879 | ||
|
|
82cc528c49 | ||
|
|
1df64031c8 | ||
|
|
ea2d181741 | ||
|
|
3cd177bff2 | ||
|
|
132fc181cd | ||
|
|
987840e480 | ||
|
|
86096708da | ||
|
|
635f0606e0 | ||
|
|
3d15a108af | ||
|
|
254b204d6c | ||
|
|
ac645c63d3 | ||
|
|
0b9f1cc3b9 | ||
|
|
b96fee95f3 | ||
|
|
8cb7fb71d1 | ||
|
|
aac6385dc6 | ||
|
|
f7ee165f43 | ||
|
|
7132b75ffb | ||
|
|
bdd4854b0d | ||
|
|
8396e40fa0 | ||
|
|
71b06f4b20 | ||
|
|
a5274daeaa | ||
|
|
36f51c427b | ||
|
|
b3d102419b | ||
|
|
5c304c002b | ||
|
|
f96e529230 | ||
|
|
717f78ce7f |
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
external/** linguist-vendored
|
||||
plugins/libimhex-rust/imgui-rs/** linguist-vendored
|
||||
plugins/libimhex-rust/imgui-sys/** linguist-vendored
|
||||
4
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -34,6 +34,10 @@ body:
|
||||
placeholder: X.X.X
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
options:
|
||||
- label: Nightly or built from sources
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context?
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@@ -18,4 +18,4 @@ body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
options:
|
||||
- label: I can provide PoC for that feature or am willing to work on it myself and submit a PR
|
||||
- label: I can provide a PoC for this feature or am willing to work on it myself and submit a PR
|
||||
53
.github/workflows/analysis.yml
vendored
Normal file
53
.github/workflows/analysis.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
codeql:
|
||||
name: 🐛 CodeQL
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: ✋ Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: 'cpp'
|
||||
|
||||
- name: 📜 Restore cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.ccache
|
||||
key: ${{ runner.os }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-build-
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo bash dist/get_deps_debian.sh
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-10 CXX=g++-10 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
..
|
||||
make -j 4 install
|
||||
|
||||
- name: 🗯️ Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
139
.github/workflows/build.yml
vendored
139
.github/workflows/build.yml
vendored
@@ -20,47 +20,85 @@ jobs:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Restore cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.ccache
|
||||
.flatpak-builder
|
||||
key: ${{ runner.os }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-build-
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo bash dist/get_deps_debian.sh
|
||||
|
||||
- name: ✋ Build
|
||||
run: |
|
||||
# Get path to magic db
|
||||
MAGICDB_PATH=$(file --version | grep -oP "(?<=magic file from ).+")
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
|
||||
sh rustup-init.sh -y --default-toolchain none
|
||||
rm rustup-init.sh
|
||||
$HOME/.cargo/bin/rustup install nightly
|
||||
$HOME/.cargo/bin/rustup target add x86_64-unknown-linux-gnu
|
||||
$HOME/.cargo/bin/rustup default nightly
|
||||
|
||||
mkdir build
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-10 CXX=g++-10 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DEXTRA_MAGICDBS="$MAGICDB_PATH" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||
..
|
||||
make -j 4 install
|
||||
|
||||
- name: ✋ Bundle Flatpak
|
||||
- name: 📦 Bundle Flatpak
|
||||
run: |
|
||||
sudo apt install flatpak flatpak-builder
|
||||
flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
flatpak --user install -y flathub org.freedesktop.Platform//20.08
|
||||
flatpak --user install -y flathub org.freedesktop.Sdk//20.08
|
||||
flatpak-builder --repo=imhex _flatpak dist/net.werwolv.ImHex.yaml
|
||||
flatpak-builder --repo=imhex _flatpak dist/net.werwolv.ImHex.yaml --ccache --keep-build-dirs
|
||||
flatpak build-bundle imhex imhex.flatpak net.werwolv.ImHex stable
|
||||
|
||||
- name: 📦 Bundle DEB
|
||||
run: |
|
||||
dpkg-deb --build build/install
|
||||
mv build/install.deb imhex.deb
|
||||
|
||||
- name: 📦 Upload ELF
|
||||
- name: 📦 Bundle AppImage
|
||||
run: |
|
||||
dist/AppImage/package.sh build
|
||||
mv build/ImHex-x86_64.AppImage imhex.AppImage
|
||||
|
||||
- name: ⬆️ Upload ELF
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Linux ELF
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
- name: 📦 Upload Flatpak
|
||||
- name: ⬆️ Upload Flatpak
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Linux Flatpak
|
||||
path: |
|
||||
imhex.flatpak
|
||||
imhex.flatpak
|
||||
|
||||
- name: ⬆️ Upload .deb
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Linux DEB
|
||||
path: |
|
||||
imhex.deb
|
||||
|
||||
- name: ⬆️ Upload AppImage
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Linux AppImage
|
||||
path: |
|
||||
imhex.AppImage
|
||||
|
||||
win:
|
||||
runs-on: windows-latest
|
||||
@@ -68,51 +106,84 @@ jobs:
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
env:
|
||||
CCACHE_DIR: "${{ github.workspace }}/.ccache"
|
||||
CCACHE_MAXSIZE: "1000M"
|
||||
CCACHE_COMPRESS: "true"
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: 🟦 Install msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: mingw64
|
||||
pacboy: >-
|
||||
gcc:p
|
||||
cmake:p
|
||||
make:p
|
||||
ccache:p
|
||||
capstone:p
|
||||
glfw:p
|
||||
file:p
|
||||
mbedtls:p
|
||||
python:p
|
||||
freetype:p
|
||||
dlfcn:p
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
bash dist/get_deps_msys2.sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://win.rustup.rs > rustup-init.exe
|
||||
./rustup-init.exe -y --default-host=x86_64-pc-windows-gnu --default-toolchain=none
|
||||
rm rustup-init.exe
|
||||
$USERPROFILE/.cargo/bin/rustup.exe target add x86_64-pc-windows-gnu
|
||||
$USERPROFILE/.cargo/bin/rustup.exe default nightly
|
||||
|
||||
- name: ✋ Build
|
||||
- name: 📜 Prepare Cache
|
||||
id: prep-ccache
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir build
|
||||
mkdir -p "${CCACHE_DIR}"
|
||||
echo "::set-output name=dir::$CCACHE_DIR"
|
||||
|
||||
- name: 📜 Restore Cache
|
||||
uses: actions/cache@v1
|
||||
id: cache-ccache
|
||||
with:
|
||||
path: ${{ steps.prep-ccache.outputs.dir }}
|
||||
key: ${{ runner.os }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-build-
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
# Get path to mingw python library
|
||||
PYTHON_LIB_NAME=$(pkg-config --libs-only-l python3 | sed 's/^-l//' | sed 's/ //')
|
||||
PYTHON_LIB_PATH=$(cygpath -m $(which lib${PYTHON_LIB_NAME}.dll))
|
||||
|
||||
# Get path to magic db
|
||||
MAGICDB_PATH=$(cygpath -m $(file --version | grep -oP "(?<=magic file from ).+"))
|
||||
|
||||
echo Python_LIBRARY: $PYTHON_LIB_PATH
|
||||
echo MagicDB Path: $MAGICDB_PATH
|
||||
|
||||
cmake -G "MinGW Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DPython_LIBRARY="$PYTHON_LIB_PATH" \
|
||||
-DEXTRA_MAGICDBS="$MAGICDB_PATH" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DRUST_PATH="$USERPROFILE/.cargo/bin/" \
|
||||
..
|
||||
mingw32-make -j4
|
||||
mingw32-make install
|
||||
mingw32-make -j4 install
|
||||
cpack
|
||||
|
||||
- name: 📦 Upload Portable ZIP
|
||||
- name: ⬆️ Upload Portable ZIP
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Windows Portable ZIP
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
- name: 📦 Upload Windows Installer
|
||||
- name: ⬆️ Upload Windows Installer
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Windows Installer
|
||||
@@ -120,7 +191,6 @@ jobs:
|
||||
build/*.msi
|
||||
|
||||
macos:
|
||||
if: false
|
||||
runs-on: macos-11.0
|
||||
name: 🍎 macOS 11.0
|
||||
steps:
|
||||
@@ -135,9 +205,17 @@ jobs:
|
||||
run: |
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
|
||||
- name: ✋ Build
|
||||
- name: 📜 Restore cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.ccache
|
||||
key: ${{ runner.os }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-build-
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir build
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=$(brew --prefix llvm)/bin/clang \
|
||||
CXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
@@ -147,10 +225,11 @@ jobs:
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
..
|
||||
make -j 4 package
|
||||
make -j4 package
|
||||
|
||||
- name: 📦 Upload DMG
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: macOS DMG
|
||||
|
||||
71
.github/workflows/codeql-analysis.yml
vendored
71
.github/workflows/codeql-analysis.yml
vendored
@@ -1,71 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '21 0 * * 2'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo bash dist/get_deps_debian.sh
|
||||
- name: Build
|
||||
run: |
|
||||
# Get path to magic db
|
||||
MAGICDB_PATH=$(file --version | grep -oP "(?<=magic file from ).+")
|
||||
mkdir build
|
||||
cd build
|
||||
CC=gcc-10 CXX=g++-10 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DEXTRA_MAGICDBS="$MAGICDB_PATH" \
|
||||
..
|
||||
make -j 4 install
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
52
.github/workflows/tests.yml
vendored
Normal file
52
.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
name: "Unit Tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: 🧪 Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Restore cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.ccache
|
||||
key: ${{ runner.os }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-build-
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo bash dist/get_deps_debian.sh
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-10 CXX=g++-10 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
..
|
||||
make -j 4 install
|
||||
|
||||
- name: 🧪 Perform Unit Tests
|
||||
run: |
|
||||
cd build
|
||||
ctest
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -12,3 +12,6 @@ build*/
|
||||
*.mgc
|
||||
imgui.ini
|
||||
.DS_Store
|
||||
plugins/.rustc_info.json
|
||||
|
||||
**/target
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# Updating the version here will update it throughout ImHex as well
|
||||
set(IMHEX_VERSION "1.9.0")
|
||||
set(IMHEX_VERSION "1.11.2")
|
||||
project(imhex VERSION ${IMHEX_VERSION})
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
@@ -14,12 +14,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
set(PLUGINS
|
||||
builtin
|
||||
windows
|
||||
# example
|
||||
)
|
||||
|
||||
# List extra magic databases to compile here
|
||||
set(MAGICDBS
|
||||
magic_dbs/nintendo_magic
|
||||
# example_cpp
|
||||
# example_rust
|
||||
)
|
||||
|
||||
findLibraries()
|
||||
@@ -27,29 +23,14 @@ findLibraries()
|
||||
detectOS()
|
||||
detectArch()
|
||||
|
||||
if (NOT USE_SYSTEM_LLVM)
|
||||
add_subdirectory(external/llvm)
|
||||
else()
|
||||
find_package(LLVM REQUIRED Demangle)
|
||||
endif()
|
||||
if (NOT USE_SYSTEM_YARA)
|
||||
add_subdirectory(external/yara)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara)
|
||||
endif()
|
||||
|
||||
# Add bundled dependencies
|
||||
add_subdirectory(plugins/libimhex)
|
||||
|
||||
# Add include directories
|
||||
include_directories(include ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${Python_INCLUDE_DIRS})
|
||||
if (USE_SYSTEM_LLVM)
|
||||
include_directories(include ${LLVM_INCLUDE_DIRS})
|
||||
endif()
|
||||
if (USE_SYSTEM_YARA)
|
||||
include_directories(include ${YARA_INCLUDE_DIRS})
|
||||
endif()
|
||||
include_directories(include)
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
|
||||
addVersionDefines()
|
||||
configurePackageCreation()
|
||||
@@ -91,17 +72,17 @@ add_executable(imhex ${application_type}
|
||||
source/views/view_yara.cpp
|
||||
source/views/view_constants.cpp
|
||||
source/views/view_store.cpp
|
||||
source/views/view_diff.cpp
|
||||
|
||||
${imhex_icon}
|
||||
)
|
||||
|
||||
set_target_properties(imhex PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
||||
target_link_directories(imhex PRIVATE ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(imhex ${CMAKE_DL_LIBS} capstone LLVMDemangle libimhex ${Python_LIBRARIES} wsock32 ws2_32 libyara Dwmapi.lib dl)
|
||||
target_link_libraries(imhex dl libimhex wsock32 ws2_32 Dwmapi.lib)
|
||||
else ()
|
||||
target_link_libraries(imhex ${CMAKE_DL_LIBS} capstone LLVMDemangle libimhex ${Python_LIBRARIES} dl pthread libyara)
|
||||
target_link_libraries(imhex dl libimhex pthread)
|
||||
endif ()
|
||||
|
||||
createPackage()
|
||||
|
||||
68
README.md
68
README.md
@@ -4,7 +4,8 @@
|
||||
|
||||
<p align="center">
|
||||
<a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild"><img alt="'Build' workflow Status" src="https://img.shields.io/github/workflow/status/WerWolv/ImHex/Build?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions"></a>
|
||||
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY"><img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&style=for-the-badge"></a>
|
||||
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY"><img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&style=for-the-badge"></a>
|
||||
<a title="Total Downloads" href="https://github.com/WerWolv/ImHex/releases/latest"><img alt="Total Downloads" src="https://img.shields.io/github/downloads/WerWolv/ImHex/total?longCache=true&style=for-the-badge&label=Downloads&logoColor=fff&logo=GitHub"></a>
|
||||
</p>
|
||||
|
||||
## Supporting
|
||||
@@ -17,6 +18,11 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
<a href="https://werwolv.net/donate"><img src="https://werwolv.net/assets/paypal_banner.png" alt="PayPal donate button" /> </a>
|
||||
</p>
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- Featureful hex view
|
||||
@@ -33,7 +39,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
- Goto from start, end and current cursor position
|
||||
- Custom C++-like pattern language for parsing highlighting a file's content
|
||||
- Automatic loading based on MIME type
|
||||
- arrays, pointers, structs, unions, enums, bitfields, using declarations, little and big endian support, conditionals and much more!
|
||||
- arrays, pointers, structs, unions, enums, bitfields, namespaces, little and big endian support, conditionals and much more!
|
||||
- Useful error messages, syntax highlighting and error marking
|
||||
- Data importing
|
||||
- Base64 files
|
||||
@@ -71,23 +77,36 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
- Entropy graph
|
||||
- Highest and average entropy
|
||||
- Encrypted / Compressed file detection
|
||||
- Built-in Content Store
|
||||
- Download all files found in the database directly from within ImHex
|
||||
- Yara Rules support
|
||||
- Quickly scan a file for vulnearabilities with official yara rules
|
||||
- Helpful tools
|
||||
- Itanium and MSVC demangler
|
||||
- ASCII table
|
||||
- Regex replacer
|
||||
- Mathematical expression evaluator (Calculator)
|
||||
- Hexadecimal Color picker
|
||||
- Base converter
|
||||
- UNIX Permissions calculator
|
||||
- Anonfiles File upload tool
|
||||
- Wikipedia term definition finder
|
||||
- File utilities
|
||||
- File splitter
|
||||
- File combiner
|
||||
- File shredderer
|
||||
- Built-in cheat sheet for pattern language and Math evaluator
|
||||
- Doesn't burn out your retinas when used in late-night sessions
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||
|
||||
## Pattern Language
|
||||
|
||||
The custom C-like Pattern Language developed and used by ImHex is easy to read, understand and learn. A guide with all features of the language can be found [in the wiki](https://github.com/WerWolv/ImHex/wiki/Pattern-Language-Guide) or a simpler version in ImHex under `Help -> Pattern Language Cheat Sheet`
|
||||
The custom C-like Pattern Language developed and used by ImHex is easy to read, understand and learn. A guide with all features of the language can be found [on the docs page](http://imhex.werwolv.net/docs).
|
||||
|
||||
## Plugin development
|
||||
|
||||
To develop plugins for ImHex, use one of the following two templates projects to get startet. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
|
||||
- [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
|
||||
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
|
||||
|
||||
## Additional Files
|
||||
|
||||
@@ -98,25 +117,22 @@ For format patterns, includable libraries and magic files, check out the [ImHex-
|
||||
Nightlies are available via GitHub Actions [here](https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild).
|
||||
|
||||
- Windows • __x86_64__
|
||||
- [MSI Installer](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Installer.zip)
|
||||
- [Portable ZIP](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Portable%20ZIP.zip)
|
||||
- [MSI](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Installer.zip)
|
||||
- [EXE](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Portable%20ZIP.zip)
|
||||
- MacOS • __x86_64__
|
||||
- [DMG](https://nightly.link/WerWolv/ImHex/workflows/build/master/macOS%20DMG.zip)
|
||||
- Linux • __x86_64__
|
||||
- [ELF](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20ELF.zip)
|
||||
- [Flatpak](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20Flatpak.zip)
|
||||
|
||||
## Compiling
|
||||
|
||||
You need a C++20 compatible compiler such as GCC 10.2.0 to compile ImHex. Moreover, the following dependencies are needed for compiling ImHex:
|
||||
You need a C++20 compatible compiler such as GCC 10.2.0 to compile ImHex.
|
||||
|
||||
- GLFW3
|
||||
- libmagic, libgnurx, libtre, libintl, libiconv
|
||||
- libmbedtls
|
||||
- capstone
|
||||
- Python3
|
||||
- freetype2
|
||||
- Brew (macOS only)
|
||||
- Xcode (macOS only)
|
||||
Many dependencies are bundled into the repository using submodules so make sure to clone it using the `--recurse-submodules` option.
|
||||
All dependencies that aren't bundled, can be installed using the dependency installer scripts found in the `/dist` folder.
|
||||
|
||||
For working examples
|
||||
|
||||
### Windows
|
||||
|
||||
@@ -199,9 +215,19 @@ with the environment variables `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`,
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
|
||||
- [Mary](https://github.com/Thog) for her immense help porting ImHex to MacOS and help during development
|
||||
- [Roblabla](https://github.com/Roblabla) for adding MSI Installer support to ImHex
|
||||
- [jam1garner](https://github.com/jam1garner) and [raytwo](https://github.com/raytwo) for their help with adding Rust support to plugins
|
||||
- All other people that have been reporting issues on Discord or GitHub that I had great conversations with :)
|
||||
|
||||
### Libraries
|
||||
|
||||
- Thanks a lot to ocornut for their amazing [Dear ImGui](https://github.com/ocornut/imgui) which is used for building the entire interface
|
||||
- Thanks to orconut as well for their hex editor view used as base for this project.
|
||||
- Thanks to ocornut as well for their hex editor view used as base for this project.
|
||||
- Thanks to BalazsJako for their incredible [ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit) used for the pattern language syntax highlighting
|
||||
- Thanks to AirGuanZ for their amazing [imgui-filebrowser](https://github.com/AirGuanZ/imgui-filebrowser) used for loading and saving files
|
||||
- Thanks to nlohmann for their [json](https://github.com/nlohmann/json) library used for project files
|
||||
- Thanks to aquynh for [capstone](https://github.com/aquynh/capstone) which is the base of the disassembly window
|
||||
- Thanks to vitaut for their [libfmt](https://github.com/fmtlib/fmt) library which makes formatting and logging so much better
|
||||
- Thanks to rxi for [microtar](https://github.com/rxi/microtar) used for extracting downloaded store assets
|
||||
|
||||
@@ -37,9 +37,9 @@ macro(findLibraries)
|
||||
# Find packages
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
find_package(mbedTLS REQUIRED)
|
||||
find_package(mbedTLS 2.26.0 REQUIRED)
|
||||
|
||||
pkg_search_module(CAPSTONE REQUIRED capstone)
|
||||
pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone)
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
@@ -60,9 +60,9 @@ macro(findLibraries)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} -DPYTHON_VERSION_MAJOR_MINOR=\"\\\"${PYTHON_VERSION_MAJOR_MINOR}\"\\\"")
|
||||
|
||||
pkg_search_module(MAGIC libmagic)
|
||||
pkg_search_module(MAGIC libmagic>=5.39)
|
||||
if(NOT MAGIC_FOUND)
|
||||
find_library(MAGIC magic REQUIRED)
|
||||
find_library(MAGIC 5.39 magic REQUIRED)
|
||||
else()
|
||||
set(MAGIC_INCLUDE_DIRS ${MAGIC_INCLUDEDIR})
|
||||
endif()
|
||||
@@ -84,10 +84,10 @@ macro(detectOS)
|
||||
set(MAGIC_INSTALL_LOCATION "magic")
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOS_LINUX")
|
||||
set(CMAKE_INSTALL_BINDIR "bin")
|
||||
set(CMAKE_INSTALL_LIBDIR "lib")
|
||||
set(PLUGINS_INSTALL_LOCATION "share/imhex/plugins")
|
||||
set(MAGIC_INSTALL_LOCATION "share/imhex/magic")
|
||||
set(CMAKE_INSTALL_BINDIR "usr/bin")
|
||||
set(CMAKE_INSTALL_LIBDIR "usr/lib")
|
||||
set(PLUGINS_INSTALL_LOCATION "usr/share/imhex/plugins")
|
||||
set(MAGIC_INSTALL_LOCATION "usr/share/imhex/magic")
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown / unsupported system!")
|
||||
endif()
|
||||
@@ -114,7 +114,7 @@ macro(configurePackageCreation)
|
||||
set(application_type)
|
||||
set(imhex_icon "${CMAKE_SOURCE_DIR}/res/resource.rc")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--allow-multiple-definition")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wl,-subsystem,windows")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-subsystem,windows")
|
||||
|
||||
if (CREATE_PACKAGE)
|
||||
set(CPACK_GENERATOR "WIX")
|
||||
@@ -157,18 +157,37 @@ macro(createPackage)
|
||||
add_subdirectory("plugins/${plugin}")
|
||||
if (TARGET ${plugin})
|
||||
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
if (WIN32)
|
||||
install(TARGETS ${plugin} RUNTIME DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||
set_target_properties(${plugin} PROPERTIES CARGO_BUILD_TARGET_DIR ${CMAKE_BINARY_DIR}/plugins)
|
||||
|
||||
get_target_property(IS_RUST_PROJECT ${plugin} RUST_PROJECT)
|
||||
|
||||
if (IS_RUST_PROJECT)
|
||||
set_target_properties(${plugin} PROPERTIES CARGO_BUILD_TARGET_DIR ${CMAKE_BINARY_DIR}/plugins)
|
||||
|
||||
get_target_property(PLUGIN_LOCATION ${plugin} LOCATION)
|
||||
|
||||
install(FILES "${PLUGIN_LOCATION}/../${plugin}.hexplug" DESTINATION "${PLUGINS_INSTALL_LOCATION}")
|
||||
else ()
|
||||
install(TARGETS ${plugin} LIBRARY DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
if (WIN32)
|
||||
install(TARGETS ${plugin} RUNTIME DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||
elseif (APPLE)
|
||||
if (CREATE_BUNDLE)
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:imhex>/${PLUGINS_INSTALL_LOCATION})
|
||||
else ()
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
endif ()
|
||||
else ()
|
||||
install(TARGETS ${plugin} LIBRARY DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
add_dependencies(imhex ${plugin})
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
set_target_properties(libimhex PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
install(TARGETS libimhex RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
if (WIN32)
|
||||
# Install binaries directly in the prefix, usually C:\Program Files\ImHex.
|
||||
@@ -176,7 +195,7 @@ macro(createPackage)
|
||||
|
||||
# Grab all dynamically linked dependencies.
|
||||
INSTALL(CODE "set(CMAKE_INSTALL_BINDIR \"${CMAKE_INSTALL_BINDIR}\")")
|
||||
INSTALL(CODE "get_filename_component(PY_PARENT ${Python_LIBRARIES} DIRECTORY)")
|
||||
INSTALL(CODE "get_filename_component(PY_PARENT \"${Python_LIBRARIES}\" DIRECTORY)")
|
||||
INSTALL(CODE "LIST(APPEND DEP_FOLDERS \${PY_PARENT})")
|
||||
install(CODE [[
|
||||
file(GET_RUNTIME_DEPENDENCIES
|
||||
@@ -203,37 +222,14 @@ macro(createPackage)
|
||||
FILES "${_file}"
|
||||
)
|
||||
endforeach()
|
||||
]])
|
||||
]])
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/dist/DEBIAN/control.in ${CMAKE_BINARY_DIR}/DEBIAN/control)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/DEBIAN/control DESTINATION ${CMAKE_INSTALL_PREFIX}/DEBIAN)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/share/applications)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/res/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/share/pixmaps RENAME imhex.png)
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
string(REPLACE ":" ";" EXTRA_MAGICDBS "${EXTRA_MAGICDBS}")
|
||||
endif ()
|
||||
|
||||
if (NOT EXTRA_MAGICDBS STREQUAL "")
|
||||
list(GET EXTRA_MAGICDBS -1 EXTRA_MAGICDBS)
|
||||
|
||||
if (NOT EXTRA_MAGICDBS STREQUAL "NOTFOUND")
|
||||
if (EXTRA_MAGICDBS MATCHES ".*\\.mgc")
|
||||
install(FILES "${EXTRA_MAGICDBS}" DESTINATION ${MAGIC_INSTALL_LOCATION})
|
||||
else ()
|
||||
install(FILES "${EXTRA_MAGICDBS}.mgc" DESTINATION ${MAGIC_INSTALL_LOCATION})
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# Compile the imhex-specific magicdb
|
||||
add_custom_target(magic_dbs ALL
|
||||
SOURCES ${MAGICDBS}
|
||||
)
|
||||
add_custom_command(TARGET magic_dbs
|
||||
COMMAND file -C -m ${CMAKE_SOURCE_DIR}/magic_dbs
|
||||
)
|
||||
|
||||
|
||||
# Install the magicdb files.
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/magic_dbs.mgc DESTINATION ${MAGIC_INSTALL_LOCATION} RENAME imhex.mgc)
|
||||
|
||||
if (CREATE_BUNDLE)
|
||||
include(PostprocessBundle)
|
||||
|
||||
|
||||
@@ -26,9 +26,8 @@ get_filename_component(BUNDLE_PATH "${BUNDLE_PATH}" ABSOLUTE)
|
||||
message(STATUS "Fixing up application bundle: ${BUNDLE_PATH}")
|
||||
|
||||
|
||||
# Make sure to fix up any additional shared libraries (like plugins) that are
|
||||
# needed.
|
||||
file(GLOB_RECURSE extra_libs "${BUNDLE_PATH}/Contents/MacOS/*.dylib")
|
||||
# Make sure to fix up any included ImHex plugin.
|
||||
file(GLOB_RECURSE extra_libs "${BUNDLE_PATH}/Contents/MacOS/plugins/*.hexplug")
|
||||
|
||||
message(STATUS "Fixing up application bundle: ${extra_dirs}")
|
||||
|
||||
|
||||
40
dist/AppImage/Dockerfile
vendored
Normal file
40
dist/AppImage/Dockerfile
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
FROM debian:bullseye-slim
|
||||
LABEL maintainer Example <example@example.com>
|
||||
|
||||
ARG TAG=master
|
||||
ARG REPO=https://github.com/WerWolv/ImHex.git
|
||||
|
||||
USER root
|
||||
|
||||
# Bring packages up to date
|
||||
RUN apt-get update \
|
||||
&& apt-get upgrade -y \
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get install -y \
|
||||
git \
|
||||
cmake \
|
||||
curl \
|
||||
squashfs-tools
|
||||
|
||||
# Fetch source and dependencies
|
||||
RUN mkdir -p /source \
|
||||
&& cd /source \
|
||||
&& git clone $REPO \
|
||||
&& cd ImHex \
|
||||
&& git checkout $TAG \
|
||||
&& git submodule update --init --recursive \
|
||||
&& cd /source/ImHex/dist \
|
||||
&& ./get_deps_debian.sh
|
||||
|
||||
ARG CXX=g++-10
|
||||
|
||||
# Build ImHex
|
||||
RUN mkdir -p /source/ImHex/build \
|
||||
&& cd /source/ImHex/build \
|
||||
&& cmake --install-prefix /usr -DCMAKE_BUILD_TYPE=Release .. \
|
||||
&& make -j
|
||||
|
||||
# Prepare for AppImage
|
||||
RUN cd /source/ImHex/dist/AppImage \
|
||||
&& ./package.sh /source/ImHex/build \
|
||||
&& mv /source/ImHex/build/ImHex-x86_64.AppImage /
|
||||
6
dist/AppImage/ImHex.desktop
vendored
Normal file
6
dist/AppImage/ImHex.desktop
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Name=ImHex
|
||||
Exec=imhex
|
||||
Icon=imhex
|
||||
Type=Application
|
||||
Categories=Utility;
|
||||
22
dist/AppImage/README.md
vendored
Normal file
22
dist/AppImage/README.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# Building an AppImage
|
||||
There are two ways of building an AppImage for ImHex, using the provided
|
||||
tools here.
|
||||
|
||||
If you want to create an AppImage and do not have a build to work from
|
||||
already, you can use docker to build ImHex and package an AppImage.
|
||||
|
||||
Alternatively you can create an AppImage using an existing build.
|
||||
|
||||
## Using docker
|
||||
First run `build.sh` to create a docker image. Then run `extract.sh` to get the
|
||||
AppImage out. This needs to be in two steps, as a docker build cannot copy
|
||||
files out. Nor can docker build use volume mounts.
|
||||
|
||||
The environment variable TAG can be set to build for a specific git tag.
|
||||
Without the master branch is build.
|
||||
|
||||
## Using an existing build
|
||||
Run `package.sh` with the build dir as an argument. E.g.:
|
||||
```
|
||||
./package.sh ../../build
|
||||
```
|
||||
16
dist/AppImage/build.sh
vendored
Executable file
16
dist/AppImage/build.sh
vendored
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set the TAG environment variable to build a specific tag
|
||||
# Set the REPO environment variable to point at a different git repository
|
||||
|
||||
# Make sure we're in the same directory as this script
|
||||
pushd $(dirname "$(realpath "$0")")
|
||||
|
||||
BUILDARG=""
|
||||
SUFFIX=""
|
||||
[ -n "${TAG}" ] && BUILDARG="${BUILDARG} --build-arg=TAG=${TAG}" && SUFFIX=":${TAG}"
|
||||
[ -n "${REPO}" ] && BUILDARG="${BUILDARG} --build-arg=REPO=${REPO}"
|
||||
|
||||
docker build ${BUILDARG} -t imhex-appimage-build${SUFFIX} .
|
||||
|
||||
popd
|
||||
26
dist/AppImage/extract.sh
vendored
Executable file
26
dist/AppImage/extract.sh
vendored
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set the TAG environment variable to move to a versioned name while extracting
|
||||
|
||||
# Make sure we're in the same directory as this script
|
||||
pushd $(dirname "$(realpath "$0")")
|
||||
|
||||
SUFFIX=""
|
||||
[ -n "$TAG" ] && SUFFIX=":$TAG"
|
||||
|
||||
# Remove old containers
|
||||
docker rm imhex 2>&1 > /dev/null
|
||||
|
||||
docker run -d --name imhex imhex-appimage-build${SUFFIX} sleep 30 &
|
||||
sleep 15
|
||||
docker cp imhex:/ImHex-x86_64.AppImage .
|
||||
|
||||
# Move to tagged name if $TAG set
|
||||
if [ -n "$TAG" ]; then
|
||||
mv ImHex-x86_64.AppImage ImHex-${TAG}-x86_64.AppImage
|
||||
echo -e "\nThe created AppImage can be found here:\n $(pwd)/ImHex-${TAG}-x86_64.AppImage\n\n"
|
||||
else
|
||||
echo -e "\nThe created AppImage can be found here:\n $(pwd)/ImHex-x86_64.AppImage\n\n"
|
||||
fi
|
||||
|
||||
popd
|
||||
BIN
dist/AppImage/imhex.png
vendored
Normal file
BIN
dist/AppImage/imhex.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
56
dist/AppImage/package.sh
vendored
Executable file
56
dist/AppImage/package.sh
vendored
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
set -e # Exit on error
|
||||
set -o pipefail # Bash specific
|
||||
|
||||
usage() {
|
||||
echo "Tool to package an ImHex build into an AppImage"
|
||||
echo
|
||||
echo "Usage:"
|
||||
echo "$0 <build dir>"
|
||||
echo
|
||||
exit
|
||||
}
|
||||
|
||||
MYDIR=$(dirname "$(realpath "$0")")
|
||||
|
||||
# Check is a build dir has been specified and it's a dir
|
||||
[ -z "$1" ] && usage
|
||||
[ -d "$1" ] || usage
|
||||
|
||||
set -u # Throw errors when unset variables are used
|
||||
|
||||
BUILDDIR=$1
|
||||
APPDIR=${BUILDDIR}/ImHex.AppDir
|
||||
APPIMAGE=${BUILDDIR}/ImHex-x86_64.AppImage
|
||||
|
||||
# Prepare for AppImage
|
||||
## Fetch the needed AppImage binaries
|
||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/AppRun-x86_64 -o ${MYDIR}/AppRun-x86_64
|
||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/runtime-x86_64 -o ${MYDIR}/runtime-x86_64
|
||||
|
||||
## Setup directory structure
|
||||
mkdir -p ${BUILDDIR}/ImHex.AppDir/usr/{bin,lib} ${BUILDDIR}/ImHex.AppDir/usr/share/imhex/plugins
|
||||
|
||||
## Add ImHex files to structure
|
||||
cp ${BUILDDIR}/imhex ${APPDIR}/usr/bin
|
||||
cp ${BUILDDIR}/plugins/builtin/builtin.hexplug ${APPDIR}/usr/share/imhex/plugins
|
||||
cp ${MYDIR}/{AppRun-x86_64,ImHex.desktop,imhex.png} ${APPDIR}/
|
||||
mv ${BUILDDIR}/ImHex.AppDir/AppRun-x86_64 ${APPDIR}/AppRun
|
||||
chmod a+x ${BUILDDIR}/ImHex.AppDir/AppRun
|
||||
|
||||
## Add all dependencies
|
||||
ldd ${BUILDDIR}/imhex | awk '/ => /{print $3}' | xargs -I '{}' cp '{}' ${APPDIR}/usr/lib
|
||||
|
||||
# Package it up as described here:
|
||||
# https://github.com/AppImage/AppImageKit#appimagetool-usage
|
||||
# under 'If you want to generate an AppImage manually'
|
||||
# This builds a v2 AppImage according to
|
||||
# https://github.com/AppImage/AppImageSpec/blob/master/draft.md#type-2-image-format
|
||||
mksquashfs ${APPDIR} ${BUILDDIR}/ImHex.squashfs -root-owned -noappend
|
||||
cat ${MYDIR}/runtime-x86_64 > ${APPIMAGE}
|
||||
cat ${BUILDDIR}/ImHex.squashfs >> ${APPIMAGE}
|
||||
chmod a+x ${APPIMAGE}
|
||||
|
||||
if [ ! -f /.dockerenv ]; then
|
||||
echo -e "\nThe created AppImage can be found here:\n ${APPIMAGE}\n\n"
|
||||
fi
|
||||
1
dist/Brewfile
vendored
1
dist/Brewfile
vendored
@@ -3,6 +3,7 @@ brew "mbedtls"
|
||||
brew "capstone"
|
||||
brew "nlohmann-json"
|
||||
brew "cmake"
|
||||
brew "ccache"
|
||||
brew "python3"
|
||||
brew "freetype2"
|
||||
brew "libmagic"
|
||||
|
||||
12
dist/DEBIAN/control.in
vendored
Normal file
12
dist/DEBIAN/control.in
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
Package: ImHex
|
||||
Version: ${PROJECT_VERSION}
|
||||
Section: editors
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
License: GNU GPL-2
|
||||
Depends: libglfw3-dev, libmagic-dev, libmbedtls-dev, libcapstone-dev, python3-dev, libfreetype-dev, libgtk-3-dev, libldap2-dev
|
||||
Maintainer: WerWolv <hey@werwolv.net>
|
||||
Description: ImHex Hex Editor
|
||||
A Hex Editor for Reverse Engineers, Programmers and
|
||||
people who value their retinas when working at 3 AM.
|
||||
|
||||
11
dist/DEBIAN/imhex.desktop
vendored
Normal file
11
dist/DEBIAN/imhex.desktop
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Name=ImHex
|
||||
Comment=ImHex Hex Editor
|
||||
GenericName=Hex Editor
|
||||
Exec=/usr/bin/imhex %U
|
||||
Icon=/usr/share/pixmaps/imhex.png
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=GNOME;GTK;Development;
|
||||
StartupWMClass=imhex
|
||||
|
||||
3
dist/get_deps_debian.sh
vendored
3
dist/get_deps_debian.sh
vendored
@@ -5,7 +5,7 @@ echo "As of 2020-12, Debian stable does not include g++-10, needs debian testing
|
||||
# Tested on 2020-12-09 with Docker image bitnami/minideb:unstable
|
||||
|
||||
# Install pkgconf (adds minimum dependencies) only if the equivalent pkf-config is not already installed.
|
||||
if !which pkg-config
|
||||
if ! which pkg-config
|
||||
then
|
||||
PKGCONF="pkgconf"
|
||||
fi
|
||||
@@ -17,6 +17,7 @@ apt install -y \
|
||||
${PKGCONF:-} \
|
||||
cmake \
|
||||
make \
|
||||
ccache \
|
||||
libglfw3-dev \
|
||||
libglm-dev \
|
||||
libmagic-dev \
|
||||
|
||||
2
dist/get_deps_fedora.sh
vendored
2
dist/get_deps_fedora.sh
vendored
@@ -10,4 +10,4 @@ dnf install \
|
||||
mbedtls-devel \
|
||||
python-devel \
|
||||
freetype-devel \
|
||||
gtk3
|
||||
gtk3-devel
|
||||
|
||||
1
dist/get_deps_msys2.sh
vendored
1
dist/get_deps_msys2.sh
vendored
@@ -4,6 +4,7 @@ pacman -S --needed --noconfirm \
|
||||
mingw-w64-x86_64-gcc \
|
||||
mingw-w64-x86_64-cmake \
|
||||
mingw-w64-x86_64-make \
|
||||
mingw-w64-x86_64-ccache \
|
||||
mingw-w64-x86_64-capstone \
|
||||
mingw-w64-x86_64-glfw \
|
||||
mingw-w64-x86_64-file \
|
||||
|
||||
11
dist/imhex.desktop
vendored
Normal file
11
dist/imhex.desktop
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Name=ImHex
|
||||
Comment=ImHex Hex Editor
|
||||
GenericName=Hex Editor
|
||||
Exec=/usr/bin/imhex %U
|
||||
Icon=/usr/share/pixmaps/imhex.png
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=GNOME;GTK;Development;
|
||||
StartupWMClass=imhex
|
||||
|
||||
4
dist/net.werwolv.ImHex.yaml
vendored
4
dist/net.werwolv.ImHex.yaml
vendored
@@ -3,7 +3,7 @@ runtime: org.freedesktop.Platform
|
||||
runtime-version: '20.08'
|
||||
default-branch: stable
|
||||
sdk: org.freedesktop.Sdk
|
||||
command: imhex
|
||||
command: /usr/bin/imhex
|
||||
|
||||
finish-args:
|
||||
- --share=ipc
|
||||
@@ -68,4 +68,4 @@ modules:
|
||||
|
||||
sources:
|
||||
- type: git
|
||||
url: https://github.com/WerWolv/ImHex.git
|
||||
url: https://github.com/WerWolv/ImHex.git
|
||||
|
||||
14
external/ImGui/CMakeLists.txt
vendored
14
external/ImGui/CMakeLists.txt
vendored
@@ -7,9 +7,13 @@ find_package(PkgConfig REQUIRED)
|
||||
find_package(Freetype REQUIRED)
|
||||
pkg_search_module(GLFW REQUIRED glfw3)
|
||||
|
||||
if (UNIX)
|
||||
find_package(OpenGL REQUIRED)
|
||||
endif ()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
|
||||
add_library(imgui STATIC
|
||||
add_library(imgui OBJECT
|
||||
source/imgui.cpp
|
||||
source/imgui_demo.cpp
|
||||
source/imgui_draw.cpp
|
||||
@@ -19,6 +23,8 @@ add_library(imgui STATIC
|
||||
source/imgui_tables.cpp
|
||||
source/imgui_widgets.cpp
|
||||
|
||||
source/cimgui.cpp
|
||||
|
||||
source/TextEditor.cpp
|
||||
|
||||
source/imgui_imhex_extensions.cpp
|
||||
@@ -36,12 +42,12 @@ add_library(imgui STATIC
|
||||
|
||||
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||
|
||||
target_include_directories(imgui PUBLIC include fonts ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS})
|
||||
target_include_directories(imgui PUBLIC include fonts ${CMAKE_CURRENT_SOURCE_DIR} ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS})
|
||||
|
||||
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(imgui Freetype::Freetype glfw3 opengl32.lib)
|
||||
target_link_libraries(imgui PUBLIC Freetype::Freetype glfw3 opengl32.lib)
|
||||
elseif (UNIX)
|
||||
target_link_libraries(imgui Freetype::Freetype glfw GL)
|
||||
target_link_libraries(imgui PUBLIC Freetype::Freetype glfw OpenGL::GL)
|
||||
endif()
|
||||
|
||||
3485
external/ImGui/include/cimgui.h
vendored
Normal file
3485
external/ImGui/include/cimgui.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -61,7 +61,8 @@ namespace ImGui {
|
||||
void InfoTooltip(const char *text);
|
||||
|
||||
bool TitleBarButton(const char* label, ImVec2 size_arg);
|
||||
bool ToolBarButton(const char* symbol, ImVec4 color, ImVec2 size_arg);
|
||||
bool ToolBarButton(const char* symbol, ImVec4 color);
|
||||
bool IconButton(const char* symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
|
||||
|
||||
inline bool HasSecondPassed() {
|
||||
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
|
||||
@@ -71,6 +72,7 @@ namespace ImGui {
|
||||
Texture LoadImageFromMemory(ImU8 *buffer, int size);
|
||||
void UnloadImage(Texture &texture);
|
||||
|
||||
void OpenPopupInWindow(const char *window_name, const char *popup_name);
|
||||
|
||||
struct ImHexCustomData {
|
||||
ImVec4 Colors[ImGuiCustomCol_COUNT];
|
||||
|
||||
@@ -149,6 +149,7 @@ typedef khronos_uint8_t GLubyte;
|
||||
#define GL_FILL 0x1B02
|
||||
#define GL_VERSION 0x1F02
|
||||
#define GL_EXTENSIONS 0x1F03
|
||||
#define GL_NEAREST 0x2600
|
||||
#define GL_LINEAR 0x2601
|
||||
#define GL_TEXTURE_MAG_FILTER 0x2800
|
||||
#define GL_TEXTURE_MIN_FILTER 0x2801
|
||||
|
||||
71
external/ImGui/include/imgui_memory_editor.h
vendored
71
external/ImGui/include/imgui_memory_editor.h
vendored
@@ -92,6 +92,7 @@ struct MemoryEditor
|
||||
bool OptShowAdvancedDecoding; // = true // display advanced decoding data on the right side.
|
||||
bool OptGreyOutZeroes; // = true // display null/zero bytes using the TextDisabled color.
|
||||
bool OptUpperCaseHex; // = true // display hexadecimal values as "FF" instead of "ff".
|
||||
bool OptShowExtraInfo; // = true // display extra information about size of data and current selection
|
||||
int OptMidColsCount; // = 8 // set to 0 to disable extra spacing between every mid-cols.
|
||||
int OptAddrDigitsCount; // = 0 // number of addr digits to display (default calculated based on maximum displayed addr).
|
||||
ImU32 HighlightColor; // // background color of highlighted bytes.
|
||||
@@ -311,9 +312,8 @@ struct MemoryEditor
|
||||
size_t data_preview_addr_next = (size_t)-1;
|
||||
|
||||
if (ImGui::IsWindowFocused()) {
|
||||
if (DataEditingAddr != (size_t)-1)
|
||||
{
|
||||
// Move cursor but only apply on next frame so scrolling with be synchronized (because currently we can't change the scrolling while the window is being rendered)
|
||||
// Move cursor but only apply on next frame so scrolling with be synchronized (because currently we can't change the scrolling while the window is being rendered)
|
||||
if (DataEditingAddr != (size_t)-1) {
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && DataEditingAddr >= (size_t)Cols) { data_editing_addr_next = DataEditingAddr - Cols; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && DataEditingAddr < mem_size - Cols) { data_editing_addr_next = DataEditingAddr + Cols; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && DataEditingAddr > 0) { data_editing_addr_next = DataEditingAddr - 1; DataEditingTakeFocus = true; }
|
||||
@@ -323,7 +323,6 @@ struct MemoryEditor
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)) && DataEditingAddr > 0) { data_editing_addr_next = 0; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = mem_size - 1; DataEditingTakeFocus = true; }
|
||||
} else if (DataPreviewAddr != -1) {
|
||||
// Move cursor but only apply on next frame so scrolling with be synchronized (because currently we can't change the scrolling while the window is being rendered)
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && DataPreviewAddr >= (size_t)Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && DataPreviewAddr < mem_size - Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr + Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
@@ -333,6 +332,11 @@ struct MemoryEditor
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = 0; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)) && DataPreviewAddr < mem_size - 1) { DataPreviewAddr = data_preview_addr_next = mem_size - 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
}
|
||||
} else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape))) {
|
||||
DataPreviewAddr = data_preview_addr_next = DataPreviewAddrEnd = (size_t)-1;
|
||||
HighlightMin = HighlightMax = (size_t)-1;
|
||||
|
||||
hex::EventManager::post<hex::EventRegionSelected>(hex::Region{ (size_t)-1, 0 });
|
||||
}
|
||||
|
||||
if (data_preview_addr_next != (size_t)-1 && (data_preview_addr_next / Cols) != (data_preview_addr_backup / Cols))
|
||||
@@ -389,8 +393,8 @@ struct MemoryEditor
|
||||
bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr <= DataPreviewAddrEnd) || (addr >= DataPreviewAddrEnd && addr <= DataPreviewAddr);
|
||||
if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview)
|
||||
{
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
float highlight_width = s.GlyphWidth * 2;
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos() - ImVec2(ImGui::GetStyle().CellPadding.x / 2, 0);
|
||||
float highlight_width = s.GlyphWidth * 2 + ImGui::GetStyle().CellPadding.x / 2;
|
||||
bool is_next_byte_highlighted = (addr + 1 < mem_size) &&
|
||||
((HighlightMax != (size_t)-1 && addr + 1 < HighlightMax) ||
|
||||
(HighlightFn && HighlightFn(mem_data, addr + 1, true)) ||
|
||||
@@ -407,6 +411,23 @@ struct MemoryEditor
|
||||
color = (ImAlphaBlendColors(HighlightColor, 0x60C08080) & 0x00FFFFFF) | 0x90000000;
|
||||
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + highlight_width, pos.y + s.LineHeight), color);
|
||||
|
||||
if (is_highlight_from_preview) {
|
||||
size_t min = std::min(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
size_t max = std::max(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
|
||||
if (n == 0 || addr == min)
|
||||
draw_list->AddLine(pos, pos + ImVec2(0, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
if (n == Cols - 1 || addr == max) {
|
||||
draw_list->AddRectFilled(pos + ImVec2(highlight_width, 0), pos + ImVec2(highlight_width + 1, s.LineHeight), color);
|
||||
draw_list->AddLine(pos + ImVec2(highlight_width + 1, -1), pos + ImVec2(highlight_width + 1, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
}
|
||||
|
||||
if (addr - Cols < min)
|
||||
draw_list->AddLine(pos, pos + ImVec2(highlight_width + 1, 0), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
if (addr + Cols > max)
|
||||
draw_list->AddLine(pos + ImVec2(0, s.LineHeight), pos + ImVec2(highlight_width + 1, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
if (DataEditingAddr == addr)
|
||||
@@ -688,35 +709,19 @@ struct MemoryEditor
|
||||
const char* format_range = OptUpperCaseHex ? "Range %0*" _PRISizeT "X..%0*" _PRISizeT "X" : "Range %0*" _PRISizeT "x..%0*" _PRISizeT "x";
|
||||
const char* format_selection = OptUpperCaseHex ? "Selection %0*" _PRISizeT "X..%0*" _PRISizeT "X (%ld %s)" : "Range %0*" _PRISizeT "x..%0*" _PRISizeT "x (%ld %s)";
|
||||
|
||||
// Options menu
|
||||
if (ImGui::Button("Options"))
|
||||
ImGui::OpenPopup("options");
|
||||
if (this->OptShowExtraInfo) {
|
||||
ImGui::Text(format_range, s.AddrDigitsCount, base_display_addr, s.AddrDigitsCount, base_display_addr + mem_size - 1);
|
||||
if (DataPreviewAddr != (size_t)-1 && DataPreviewAddrEnd != (size_t)-1) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginPopup("options")) {
|
||||
ImGui::PushItemWidth(ImGui::CalcTextSize("00 cols").x * 1.1f);
|
||||
if (ImGui::DragInt("##cols", &Cols, 0.2f, 4, 32, "%d cols")) { ContentsWidthChanged = true; if (Cols < 1) Cols = 1; }
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::Checkbox("Show HexII", &OptShowHexII);
|
||||
if (ImGui::Checkbox("Show Ascii", &OptShowAscii)) { ContentsWidthChanged = true; }
|
||||
if (ImGui::Checkbox("Show Advanced Decoding", &OptShowAdvancedDecoding)) { ContentsWidthChanged = true; }
|
||||
ImGui::Checkbox("Grey out zeroes", &OptGreyOutZeroes);
|
||||
ImGui::Checkbox("Uppercase Hex", &OptUpperCaseHex);
|
||||
auto selectionStart = std::min(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
auto selectionEnd = std::max(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Text(format_range, s.AddrDigitsCount, base_display_addr, s.AddrDigitsCount, base_display_addr + mem_size - 1);
|
||||
if (DataPreviewAddr != (size_t)-1 && DataPreviewAddrEnd != (size_t)-1) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
|
||||
auto selectionStart = std::min(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
auto selectionEnd = std::max(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
|
||||
size_t regionSize = (selectionEnd - selectionStart) + 1;
|
||||
ImGui::Text(format_selection, s.AddrDigitsCount, base_display_addr + selectionStart, s.AddrDigitsCount, base_display_addr + selectionEnd, regionSize, regionSize == 1 ? "byte" : "bytes");
|
||||
size_t regionSize = (selectionEnd - selectionStart) + 1;
|
||||
ImGui::Text(format_selection, s.AddrDigitsCount, base_display_addr + selectionStart, s.AddrDigitsCount, base_display_addr + selectionEnd, regionSize, regionSize == 1 ? "byte" : "bytes");
|
||||
}
|
||||
}
|
||||
|
||||
if (GotoAddr != (size_t)-1)
|
||||
|
||||
24
external/ImGui/source/TextEditor.cpp
vendored
24
external/ImGui/source/TextEditor.cpp
vendored
@@ -767,8 +767,26 @@ void TextEditor::HandleKeyboardInputs()
|
||||
for (int i = 0; i < io.InputQueueCharacters.Size; i++)
|
||||
{
|
||||
auto c = io.InputQueueCharacters[i];
|
||||
if (c != 0 && (c == '\n' || c >= 32))
|
||||
EnterCharacter(c, shift);
|
||||
if (c != 0 && (c == '\n' || c >= 32)) {
|
||||
constexpr std::array<std::pair<char, char>, 5> doubleChars = {{ { '(', ')' }, { '[', ']' }, { '{', '}' }, { '"', '"' }, {'\'', '\'' } }};
|
||||
|
||||
bool handled = false;
|
||||
for (auto [doubleCharOpen, doubleCharClose] : doubleChars) {
|
||||
if (c == doubleCharOpen) {
|
||||
EnterCharacter(doubleCharOpen, shift);
|
||||
auto cursorPos = GetCursorPosition();
|
||||
EnterCharacter(doubleCharClose, shift);
|
||||
SetCursorPosition(cursorPos);
|
||||
|
||||
handled = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled)
|
||||
EnterCharacter(c, shift);
|
||||
}
|
||||
}
|
||||
io.InputQueueCharacters.resize(0);
|
||||
}
|
||||
@@ -1872,7 +1890,7 @@ void TextEditor::Backspace()
|
||||
|
||||
u.mRemovedStart = u.mRemovedEnd = GetActualCursorCoordinates();
|
||||
--u.mRemovedStart.mColumn;
|
||||
--mState.mCursorPosition.mColumn;
|
||||
mState.mCursorPosition.mColumn = GetCharacterColumn(mState.mCursorPosition.mLine, cindex);
|
||||
|
||||
while (cindex < line.size() && cend-- > cindex)
|
||||
{
|
||||
|
||||
4598
external/ImGui/source/cimgui.cpp
vendored
Normal file
4598
external/ImGui/source/cimgui.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
53
external/ImGui/source/imgui_imhex_extensions.cpp
vendored
53
external/ImGui/source/imgui_imhex_extensions.cpp
vendored
@@ -357,6 +357,13 @@ namespace ImGui {
|
||||
texture = { nullptr, 0, 0 };
|
||||
}
|
||||
|
||||
void OpenPopupInWindow(const char *window_name, const char *popup_name) {
|
||||
if (ImGui::Begin(window_name)) {
|
||||
ImGui::OpenPopup(popup_name);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
bool TitleBarButton(const char* label, ImVec2 size_arg) {
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
@@ -394,7 +401,7 @@ namespace ImGui {
|
||||
return pressed;
|
||||
}
|
||||
|
||||
bool ToolBarButton(const char* symbol, ImVec4 color, ImVec2 size_arg) {
|
||||
bool ToolBarButton(const char* symbol, ImVec4 color) {
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
@@ -408,7 +415,7 @@ namespace ImGui {
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
|
||||
ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
|
||||
ImVec2 size = CalcItemSize(ImVec2(1, 1) * ImGui::GetCurrentWindow()->MenuBarHeight(), label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
|
||||
|
||||
const ImRect bb(pos, pos + size);
|
||||
ItemSize(size, style.FramePadding.y);
|
||||
@@ -436,4 +443,46 @@ namespace ImGui {
|
||||
return pressed;
|
||||
}
|
||||
|
||||
bool IconButton(const char* symbol, ImVec4 color, ImVec2 size_arg) {
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
color.w = 1.0F;
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
const ImGuiID id = window->GetID(symbol);
|
||||
const ImVec2 label_size = CalcTextSize(symbol, NULL, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
|
||||
ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
|
||||
|
||||
const ImRect bb(pos, pos + size);
|
||||
ItemSize(size, style.FramePadding.y);
|
||||
if (!ItemAdd(bb, id))
|
||||
return false;
|
||||
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held);
|
||||
|
||||
PushStyleColor(ImGuiCol_Text, color);
|
||||
|
||||
// Render
|
||||
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
|
||||
RenderNavHighlight(bb, id);
|
||||
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, NULL, &label_size, style.ButtonTextAlign, &bb);
|
||||
|
||||
PopStyleColor();
|
||||
|
||||
// Automatically close popups
|
||||
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
|
||||
// CloseCurrentPopup();
|
||||
|
||||
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
|
||||
return pressed;
|
||||
}
|
||||
|
||||
}
|
||||
2
external/ImGui/source/imgui_impl_opengl3.cpp
vendored
2
external/ImGui/source/imgui_impl_opengl3.cpp
vendored
@@ -525,7 +525,7 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
glGenTextures(1, &bd->FontTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, bd->FontTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
|
||||
2
external/curl
vendored
2
external/curl
vendored
Submodule external/curl updated: bfbde883af...aceff6088c
10
external/microtar/CMakeLists.txt
vendored
Normal file
10
external/microtar/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(microtar)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
|
||||
add_library(microtar STATIC
|
||||
source/microtar.c
|
||||
)
|
||||
|
||||
target_include_directories(microtar PUBLIC include)
|
||||
19
external/microtar/LICENSE
vendored
Normal file
19
external/microtar/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2017 rxi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
99
external/microtar/README.md
vendored
Normal file
99
external/microtar/README.md
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
# microtar
|
||||
A lightweight tar library written in ANSI C
|
||||
|
||||
|
||||
## Basic Usage
|
||||
The library consists of `microtar.c` and `microtar.h`. These two files can be
|
||||
dropped into an existing project and compiled along with it.
|
||||
|
||||
|
||||
#### Reading
|
||||
```c
|
||||
mtar_t tar;
|
||||
mtar_header_t h;
|
||||
char *p;
|
||||
|
||||
/* Open archive for reading */
|
||||
mtar_open(&tar, "test.tar", "r");
|
||||
|
||||
/* Print all file names and sizes */
|
||||
while ( (mtar_read_header(&tar, &h)) != MTAR_ENULLRECORD ) {
|
||||
printf("%s (%d bytes)\n", h.name, h.size);
|
||||
mtar_next(&tar);
|
||||
}
|
||||
|
||||
/* Load and print contents of file "test.txt" */
|
||||
mtar_find(&tar, "test.txt", &h);
|
||||
p = calloc(1, h.size + 1);
|
||||
mtar_read_data(&tar, p, h.size);
|
||||
printf("%s", p);
|
||||
free(p);
|
||||
|
||||
/* Close archive */
|
||||
mtar_close(&tar);
|
||||
```
|
||||
|
||||
#### Writing
|
||||
```c
|
||||
mtar_t tar;
|
||||
const char *str1 = "Hello world";
|
||||
const char *str2 = "Goodbye world";
|
||||
|
||||
/* Open archive for writing */
|
||||
mtar_open(&tar, "test.tar", "w");
|
||||
|
||||
/* Write strings to files `test1.txt` and `test2.txt` */
|
||||
mtar_write_file_header(&tar, "test1.txt", strlen(str1));
|
||||
mtar_write_data(&tar, str1, strlen(str1));
|
||||
mtar_write_file_header(&tar, "test2.txt", strlen(str2));
|
||||
mtar_write_data(&tar, str2, strlen(str2));
|
||||
|
||||
/* Finalize -- this needs to be the last thing done before closing */
|
||||
mtar_finalize(&tar);
|
||||
|
||||
/* Close archive */
|
||||
mtar_close(&tar);
|
||||
```
|
||||
|
||||
|
||||
## Error handling
|
||||
All functions which return an `int` will return `MTAR_ESUCCESS` if the operation
|
||||
is successful. If an error occurs an error value less-than-zero will be
|
||||
returned; this value can be passed to the function `mtar_strerror()` to get its
|
||||
corresponding error string.
|
||||
|
||||
|
||||
## Wrapping a stream
|
||||
If you want to read or write from something other than a file, the `mtar_t`
|
||||
struct can be manually initialized with your own callback functions and a
|
||||
`stream` pointer.
|
||||
|
||||
All callback functions are passed a pointer to the `mtar_t` struct as their
|
||||
first argument. They should return `MTAR_ESUCCESS` if the operation succeeds
|
||||
without an error, or an integer below zero if an error occurs.
|
||||
|
||||
After the `stream` field has been set, all required callbacks have been set and
|
||||
all unused fields have been zeroset the `mtar_t` struct can be safely used with
|
||||
the microtar functions. `mtar_open` *should not* be called if the `mtar_t`
|
||||
struct was initialized manually.
|
||||
|
||||
#### Reading
|
||||
The following callbacks should be set for reading an archive from a stream:
|
||||
|
||||
Name | Arguments | Description
|
||||
--------|------------------------------------------|---------------------------
|
||||
`read` | `mtar_t *tar, void *data, unsigned size` | Read data from the stream
|
||||
`seek` | `mtar_t *tar, unsigned pos` | Set the position indicator
|
||||
`close` | `mtar_t *tar` | Close the stream
|
||||
|
||||
#### Writing
|
||||
The following callbacks should be set for writing an archive to a stream:
|
||||
|
||||
Name | Arguments | Description
|
||||
--------|------------------------------------------------|---------------------
|
||||
`write` | `mtar_t *tar, const void *data, unsigned size` | Write data to the stream
|
||||
|
||||
|
||||
## License
|
||||
This library is free software; you can redistribute it and/or modify it under
|
||||
the terms of the MIT license. See [LICENSE](LICENSE) for details.
|
||||
93
external/microtar/include/microtar.h
vendored
Normal file
93
external/microtar/include/microtar.h
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) 2017 rxi
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the MIT license. See `microtar.c` for details.
|
||||
*/
|
||||
|
||||
#ifndef MICROTAR_H
|
||||
#define MICROTAR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MTAR_VERSION "0.1.0"
|
||||
|
||||
enum {
|
||||
MTAR_ESUCCESS = 0,
|
||||
MTAR_EFAILURE = -1,
|
||||
MTAR_EOPENFAIL = -2,
|
||||
MTAR_EREADFAIL = -3,
|
||||
MTAR_EWRITEFAIL = -4,
|
||||
MTAR_ESEEKFAIL = -5,
|
||||
MTAR_EBADCHKSUM = -6,
|
||||
MTAR_ENULLRECORD = -7,
|
||||
MTAR_ENOTFOUND = -8
|
||||
};
|
||||
|
||||
enum {
|
||||
MTAR_TREG = '0',
|
||||
MTAR_TLNK = '1',
|
||||
MTAR_TSYM = '2',
|
||||
MTAR_TCHR = '3',
|
||||
MTAR_TBLK = '4',
|
||||
MTAR_TDIR = '5',
|
||||
MTAR_TFIFO = '6'
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned mode;
|
||||
unsigned owner;
|
||||
unsigned size;
|
||||
unsigned mtime;
|
||||
unsigned type;
|
||||
char name[100];
|
||||
char linkname[100];
|
||||
} mtar_header_t;
|
||||
|
||||
|
||||
typedef struct mtar_t mtar_t;
|
||||
|
||||
struct mtar_t {
|
||||
int (*read)(mtar_t *tar, void *data, unsigned size);
|
||||
|
||||
int (*write)(mtar_t *tar, const void *data, unsigned size);
|
||||
|
||||
int (*seek)(mtar_t *tar, unsigned pos);
|
||||
|
||||
int (*close)(mtar_t *tar);
|
||||
|
||||
void *stream;
|
||||
unsigned pos;
|
||||
unsigned remaining_data;
|
||||
unsigned last_header;
|
||||
};
|
||||
|
||||
|
||||
const char *mtar_strerror(int err);
|
||||
|
||||
int mtar_open(mtar_t *tar, const char *filename, const char *mode);
|
||||
int mtar_close(mtar_t *tar);
|
||||
|
||||
int mtar_seek(mtar_t *tar, unsigned pos);
|
||||
int mtar_rewind(mtar_t *tar);
|
||||
int mtar_next(mtar_t *tar);
|
||||
int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h);
|
||||
int mtar_read_header(mtar_t *tar, mtar_header_t *h);
|
||||
int mtar_read_data(mtar_t *tar, void *ptr, unsigned size);
|
||||
|
||||
int mtar_write_header(mtar_t *tar, const mtar_header_t *h);
|
||||
int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size);
|
||||
int mtar_write_dir_header(mtar_t *tar, const char *name);
|
||||
int mtar_write_data(mtar_t *tar, const void *data, unsigned size);
|
||||
int mtar_finalize(mtar_t *tar);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
376
external/microtar/source/microtar.c
vendored
Normal file
376
external/microtar/source/microtar.c
vendored
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright (c) 2017 rxi
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <microtar.h>
|
||||
|
||||
typedef struct {
|
||||
char name[100];
|
||||
char mode[8];
|
||||
char owner[8];
|
||||
char group[8];
|
||||
char size[12];
|
||||
char mtime[12];
|
||||
char checksum[8];
|
||||
char type;
|
||||
char linkname[100];
|
||||
char _padding[255];
|
||||
} mtar_raw_header_t;
|
||||
|
||||
|
||||
static unsigned round_up(unsigned n, unsigned incr) {
|
||||
return n + (incr - n % incr) % incr;
|
||||
}
|
||||
|
||||
|
||||
static unsigned checksum(const mtar_raw_header_t* rh) {
|
||||
unsigned i;
|
||||
unsigned char *p = (unsigned char*) rh;
|
||||
unsigned res = 256;
|
||||
for (i = 0; i < offsetof(mtar_raw_header_t, checksum); i++) {
|
||||
res += p[i];
|
||||
}
|
||||
for (i = offsetof(mtar_raw_header_t, type); i < sizeof(*rh); i++) {
|
||||
res += p[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int tread(mtar_t *tar, void *data, unsigned size) {
|
||||
int err = tar->read(tar, data, size);
|
||||
tar->pos += size;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int twrite(mtar_t *tar, const void *data, unsigned size) {
|
||||
int err = tar->write(tar, data, size);
|
||||
tar->pos += size;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int write_null_bytes(mtar_t *tar, int n) {
|
||||
int i, err;
|
||||
char nul = '\0';
|
||||
for (i = 0; i < n; i++) {
|
||||
err = twrite(tar, &nul, 1);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh) {
|
||||
unsigned chksum1, chksum2;
|
||||
|
||||
/* If the checksum starts with a null byte we assume the record is NULL */
|
||||
if (*rh->checksum == '\0') {
|
||||
return MTAR_ENULLRECORD;
|
||||
}
|
||||
|
||||
/* Build and compare checksum */
|
||||
chksum1 = checksum(rh);
|
||||
sscanf(rh->checksum, "%o", &chksum2);
|
||||
if (chksum1 != chksum2) {
|
||||
return MTAR_EBADCHKSUM;
|
||||
}
|
||||
|
||||
/* Load raw header into header */
|
||||
sscanf(rh->mode, "%o", &h->mode);
|
||||
sscanf(rh->owner, "%o", &h->owner);
|
||||
sscanf(rh->size, "%o", &h->size);
|
||||
sscanf(rh->mtime, "%o", &h->mtime);
|
||||
h->type = rh->type;
|
||||
strcpy(h->name, rh->name);
|
||||
strcpy(h->linkname, rh->linkname);
|
||||
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int header_to_raw(mtar_raw_header_t *rh, const mtar_header_t *h) {
|
||||
unsigned chksum;
|
||||
|
||||
/* Load header into raw header */
|
||||
memset(rh, 0, sizeof(*rh));
|
||||
sprintf(rh->mode, "%o", h->mode);
|
||||
sprintf(rh->owner, "%o", h->owner);
|
||||
sprintf(rh->size, "%o", h->size);
|
||||
sprintf(rh->mtime, "%o", h->mtime);
|
||||
rh->type = h->type ? h->type : MTAR_TREG;
|
||||
strcpy(rh->name, h->name);
|
||||
strcpy(rh->linkname, h->linkname);
|
||||
|
||||
/* Calculate and write checksum */
|
||||
chksum = checksum(rh);
|
||||
sprintf(rh->checksum, "%06o", chksum);
|
||||
rh->checksum[7] = ' ';
|
||||
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
const char* mtar_strerror(int err) {
|
||||
switch (err) {
|
||||
case MTAR_ESUCCESS : return "success";
|
||||
case MTAR_EFAILURE : return "failure";
|
||||
case MTAR_EOPENFAIL : return "could not open";
|
||||
case MTAR_EREADFAIL : return "could not read";
|
||||
case MTAR_EWRITEFAIL : return "could not write";
|
||||
case MTAR_ESEEKFAIL : return "could not seek";
|
||||
case MTAR_EBADCHKSUM : return "bad checksum";
|
||||
case MTAR_ENULLRECORD : return "null record";
|
||||
case MTAR_ENOTFOUND : return "file not found";
|
||||
}
|
||||
return "unknown error";
|
||||
}
|
||||
|
||||
|
||||
static int file_write(mtar_t *tar, const void *data, unsigned size) {
|
||||
unsigned res = fwrite(data, 1, size, tar->stream);
|
||||
return (res == size) ? MTAR_ESUCCESS : MTAR_EWRITEFAIL;
|
||||
}
|
||||
|
||||
static int file_read(mtar_t *tar, void *data, unsigned size) {
|
||||
unsigned res = fread(data, 1, size, tar->stream);
|
||||
return (res == size) ? MTAR_ESUCCESS : MTAR_EREADFAIL;
|
||||
}
|
||||
|
||||
static int file_seek(mtar_t *tar, unsigned offset) {
|
||||
int res = fseek(tar->stream, offset, SEEK_SET);
|
||||
return (res == 0) ? MTAR_ESUCCESS : MTAR_ESEEKFAIL;
|
||||
}
|
||||
|
||||
static int file_close(mtar_t *tar) {
|
||||
fclose(tar->stream);
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int mtar_open(mtar_t *tar, const char *filename, const char *mode) {
|
||||
int err;
|
||||
mtar_header_t h;
|
||||
|
||||
/* Init tar struct and functions */
|
||||
memset(tar, 0, sizeof(*tar));
|
||||
tar->write = file_write;
|
||||
tar->read = file_read;
|
||||
tar->seek = file_seek;
|
||||
tar->close = file_close;
|
||||
|
||||
/* Assure mode is always binary */
|
||||
if ( strchr(mode, 'r') ) mode = "rb";
|
||||
if ( strchr(mode, 'w') ) mode = "wb";
|
||||
if ( strchr(mode, 'a') ) mode = "ab";
|
||||
/* Open file */
|
||||
tar->stream = fopen(filename, mode);
|
||||
if (!tar->stream) {
|
||||
return MTAR_EOPENFAIL;
|
||||
}
|
||||
/* Read first header to check it is valid if mode is `r` */
|
||||
if (*mode == 'r') {
|
||||
err = mtar_read_header(tar, &h);
|
||||
if (err != MTAR_ESUCCESS) {
|
||||
mtar_close(tar);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return ok */
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int mtar_close(mtar_t *tar) {
|
||||
return tar->close(tar);
|
||||
}
|
||||
|
||||
|
||||
int mtar_seek(mtar_t *tar, unsigned pos) {
|
||||
int err = tar->seek(tar, pos);
|
||||
tar->pos = pos;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int mtar_rewind(mtar_t *tar) {
|
||||
tar->remaining_data = 0;
|
||||
tar->last_header = 0;
|
||||
return mtar_seek(tar, 0);
|
||||
}
|
||||
|
||||
|
||||
int mtar_next(mtar_t *tar) {
|
||||
int err, n;
|
||||
mtar_header_t h;
|
||||
/* Load header */
|
||||
err = mtar_read_header(tar, &h);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
/* Seek to next record */
|
||||
n = round_up(h.size, 512) + sizeof(mtar_raw_header_t);
|
||||
return mtar_seek(tar, tar->pos + n);
|
||||
}
|
||||
|
||||
|
||||
int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h) {
|
||||
int err;
|
||||
mtar_header_t header;
|
||||
/* Start at beginning */
|
||||
err = mtar_rewind(tar);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
/* Iterate all files until we hit an error or find the file */
|
||||
while ( (err = mtar_read_header(tar, &header)) == MTAR_ESUCCESS ) {
|
||||
if ( !strcmp(header.name, name) ) {
|
||||
if (h) {
|
||||
*h = header;
|
||||
}
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
mtar_next(tar);
|
||||
}
|
||||
/* Return error */
|
||||
if (err == MTAR_ENULLRECORD) {
|
||||
err = MTAR_ENOTFOUND;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int mtar_read_header(mtar_t *tar, mtar_header_t *h) {
|
||||
int err;
|
||||
mtar_raw_header_t rh;
|
||||
/* Save header position */
|
||||
tar->last_header = tar->pos;
|
||||
/* Read raw header */
|
||||
err = tread(tar, &rh, sizeof(rh));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
/* Seek back to start of header */
|
||||
err = mtar_seek(tar, tar->last_header);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
/* Load raw header into header struct and return */
|
||||
return raw_to_header(h, &rh);
|
||||
}
|
||||
|
||||
|
||||
int mtar_read_data(mtar_t *tar, void *ptr, unsigned size) {
|
||||
int err;
|
||||
/* If we have no remaining data then this is the first read, we get the size,
|
||||
* set the remaining data and seek to the beginning of the data */
|
||||
if (tar->remaining_data == 0) {
|
||||
mtar_header_t h;
|
||||
/* Read header */
|
||||
err = mtar_read_header(tar, &h);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
/* Seek past header and init remaining data */
|
||||
err = mtar_seek(tar, tar->pos + sizeof(mtar_raw_header_t));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
tar->remaining_data = h.size;
|
||||
}
|
||||
/* Read data */
|
||||
err = tread(tar, ptr, size);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
tar->remaining_data -= size;
|
||||
/* If there is no remaining data we've finished reading and seek back to the
|
||||
* header */
|
||||
if (tar->remaining_data == 0) {
|
||||
return mtar_seek(tar, tar->last_header);
|
||||
}
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int mtar_write_header(mtar_t *tar, const mtar_header_t *h) {
|
||||
mtar_raw_header_t rh;
|
||||
/* Build raw header and write */
|
||||
header_to_raw(&rh, h);
|
||||
tar->remaining_data = h->size;
|
||||
return twrite(tar, &rh, sizeof(rh));
|
||||
}
|
||||
|
||||
|
||||
int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size) {
|
||||
mtar_header_t h;
|
||||
/* Build header */
|
||||
memset(&h, 0, sizeof(h));
|
||||
strcpy(h.name, name);
|
||||
h.size = size;
|
||||
h.type = MTAR_TREG;
|
||||
h.mode = 0664;
|
||||
/* Write header */
|
||||
return mtar_write_header(tar, &h);
|
||||
}
|
||||
|
||||
|
||||
int mtar_write_dir_header(mtar_t *tar, const char *name) {
|
||||
mtar_header_t h;
|
||||
/* Build header */
|
||||
memset(&h, 0, sizeof(h));
|
||||
strcpy(h.name, name);
|
||||
h.type = MTAR_TDIR;
|
||||
h.mode = 0775;
|
||||
/* Write header */
|
||||
return mtar_write_header(tar, &h);
|
||||
}
|
||||
|
||||
|
||||
int mtar_write_data(mtar_t *tar, const void *data, unsigned size) {
|
||||
int err;
|
||||
/* Write data */
|
||||
err = twrite(tar, data, size);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
tar->remaining_data -= size;
|
||||
/* Write padding if we've written all the data for this file */
|
||||
if (tar->remaining_data == 0) {
|
||||
return write_null_bytes(tar, round_up(tar->pos, 512) - tar->pos);
|
||||
}
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int mtar_finalize(mtar_t *tar) {
|
||||
/* Write two NULL records */
|
||||
return write_null_bytes(tar, sizeof(mtar_raw_header_t) * 2);
|
||||
}
|
||||
7
external/yara/CMakeLists.txt
vendored
7
external/yara/CMakeLists.txt
vendored
@@ -94,8 +94,6 @@ set(LIBYARA_MODULES
|
||||
${LIBYARA_SOURCE_PATH}/modules/magic/magic.c)
|
||||
|
||||
# Add mbedtls crypto wrappers
|
||||
file(READ crypto_mbedtls.h MBEDTLS_CRYPTO_H)
|
||||
file(WRITE ${LIBYARA_SOURCE_PATH}/crypto.h "${MBEDTLS_CRYPTO_H}")
|
||||
add_compile_definitions("HAVE_MBEDTLS")
|
||||
|
||||
add_compile_definitions("USE_NO_PROC")
|
||||
@@ -109,10 +107,11 @@ add_compile_definitions("DEX_MODULE")
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-shift-count-overflow")
|
||||
add_library(libyara STATIC ${LIBYARA_SOURCE} ${LIBYARA_INCLUDES} ${LIBYARA_MODULES})
|
||||
set_property(TARGET libyara PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_include_directories(
|
||||
libyara
|
||||
PUBLIC $<BUILD_INTERFACE:${LIBYARA_SOURCE_PATH}/include> $<INSTALL_INTERFACE:include>
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/yara> $<BUILD_INTERFACE:${LIBYARA_SOURCE_PATH}/include> $<INSTALL_INTERFACE:include>
|
||||
PRIVATE ${LIBYARA_SOURCE_PATH} ${MBEDTLS_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
@@ -125,4 +124,4 @@ endif ()
|
||||
include(GNUInstallDirs)
|
||||
configure_file(${LIBYARA_SOURCE_PATH}/yara.pc.in
|
||||
${LIBYARA_SOURCE_PATH}/yara.pc @ONLY)
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||
|
||||
@@ -21,11 +21,11 @@ namespace hex::prv {
|
||||
explicit FileProvider(std::string path);
|
||||
~FileProvider() override;
|
||||
|
||||
bool isAvailable() override;
|
||||
bool isReadable() override;
|
||||
bool isWritable() override;
|
||||
bool isResizable() override;
|
||||
bool isSavable() override;
|
||||
bool isAvailable() const override;
|
||||
bool isReadable() const override;
|
||||
bool isWritable() const override;
|
||||
bool isResizable() const override;
|
||||
bool isSavable() const override;
|
||||
|
||||
void read(u64 offset, void *buffer, size_t size, bool overlays) override;
|
||||
void write(u64 offset, const void *buffer, size_t size) override;
|
||||
@@ -33,12 +33,13 @@ namespace hex::prv {
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override;
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override;
|
||||
size_t getActualSize() override;
|
||||
size_t getActualSize() const override;
|
||||
|
||||
void save() override;
|
||||
void saveAs(const std::string &path) override;
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> getDataInformation() override;
|
||||
[[nodiscard]] std::string getName() const override;
|
||||
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataInformation() const override;
|
||||
|
||||
private:
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
34
include/views/view_diff.hpp
Normal file
34
include/views/view_diff.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/views/view.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace prv { class Provider; }
|
||||
|
||||
class ViewDiff : public View {
|
||||
public:
|
||||
ViewDiff();
|
||||
~ViewDiff() override;
|
||||
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
private:
|
||||
void drawDiffLine(const std::array<int, 2> &providerIds, u64 row) const;
|
||||
|
||||
int m_providerA = -1, m_providerB = -1;
|
||||
|
||||
bool m_greyedOutZeros = true;
|
||||
bool m_upperCaseHex = true;
|
||||
int m_columnCount = 16;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <hex/views/view.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <cstdio>
|
||||
|
||||
namespace hex {
|
||||
@@ -17,12 +19,24 @@ namespace hex {
|
||||
void drawMenu() override;
|
||||
|
||||
private:
|
||||
enum class HashFunctions { Crc8, Crc16, Crc32, Md5, Sha1, Sha224, Sha256, Sha384, Sha512 };
|
||||
|
||||
bool m_shouldInvalidate = true;
|
||||
int m_currHashFunction = 0;
|
||||
u64 m_hashRegion[2] = { 0 };
|
||||
bool m_shouldMatchSelection = false;
|
||||
|
||||
static constexpr const char* HashFunctionNames[] = { "CRC16", "CRC32", "MD5", "SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512" };
|
||||
static constexpr std::array hashFunctionNames {
|
||||
std::pair{HashFunctions::Crc8, "CRC8"},
|
||||
std::pair{HashFunctions::Crc16, "CRC16"},
|
||||
std::pair{HashFunctions::Crc32, "CRC32"},
|
||||
std::pair{HashFunctions::Md5, "MD5"},
|
||||
std::pair{HashFunctions::Sha1, "SHA-1"},
|
||||
std::pair{HashFunctions::Sha224, "SHA-224"},
|
||||
std::pair{HashFunctions::Sha256, "SHA-256"},
|
||||
std::pair{HashFunctions::Sha384, "SHA-384"},
|
||||
std::pair{HashFunctions::Sha512, "SHA-512"},
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/views/view.hpp>
|
||||
#include <hex/pattern_language/evaluator.hpp>
|
||||
#include <hex/pattern_language/pattern_language.hpp>
|
||||
|
||||
#include <hex/pattern_language/log_console.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <cstring>
|
||||
@@ -27,10 +26,13 @@ namespace hex {
|
||||
|
||||
private:
|
||||
pl::PatternLanguage *m_patternLanguageRuntime;
|
||||
std::vector<std::string> m_possiblePatternFiles;
|
||||
int m_selectedPatternFile = 0;
|
||||
std::vector<std::filesystem::path> m_possiblePatternFiles;
|
||||
u32 m_selectedPatternFile = 0;
|
||||
bool m_runAutomatically = false;
|
||||
bool m_evaluatorRunning = false;
|
||||
bool m_hasUnevaluatedChanges = false;
|
||||
|
||||
bool m_acceptPatternWindowOpen = false;
|
||||
|
||||
TextEditor m_textEditor;
|
||||
std::vector<std::pair<pl::LogConsole::Level, std::string>> m_console;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <array>
|
||||
#include <future>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -19,6 +20,8 @@ namespace hex {
|
||||
std::string link;
|
||||
std::string hash;
|
||||
|
||||
bool isFolder;
|
||||
|
||||
bool downloading;
|
||||
bool installed;
|
||||
bool hasUpdate;
|
||||
@@ -39,8 +42,9 @@ namespace hex {
|
||||
Net m_net;
|
||||
std::future<Response<std::string>> m_apiRequest;
|
||||
std::future<Response<void>> m_download;
|
||||
std::filesystem::path m_downloadPath;
|
||||
|
||||
std::vector<StoreEntry> m_patterns, m_includes, m_magics, m_constants;
|
||||
std::vector<StoreEntry> m_patterns, m_includes, m_magics, m_constants, m_yara;
|
||||
|
||||
void drawStore();
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ namespace hex {
|
||||
|
||||
private:
|
||||
bool m_searching = false;
|
||||
bool m_regex = false;
|
||||
bool m_pattern_parsed = false;
|
||||
|
||||
std::vector<FoundString> m_foundStrings;
|
||||
std::vector<size_t> m_filterIndices;
|
||||
|
||||
@@ -18,12 +18,13 @@ namespace hex {
|
||||
private:
|
||||
struct YaraMatch {
|
||||
std::string identifier;
|
||||
std::string variable;
|
||||
s64 address;
|
||||
s32 size;
|
||||
bool wholeDataMatch;
|
||||
};
|
||||
|
||||
std::vector<std::string> m_rules;
|
||||
std::vector<std::pair<std::string, std::string>> m_rules;
|
||||
std::vector<YaraMatch> m_matches;
|
||||
u32 m_selectedRule = 0;
|
||||
bool m_matching = false;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/views/view.hpp>
|
||||
@@ -64,6 +65,8 @@ namespace hex {
|
||||
ImGui::Texture m_logoTexture;
|
||||
|
||||
std::filesystem::path m_safetyBackupPath;
|
||||
|
||||
std::list<std::string> m_popupsToOpen;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
# A libmagic database containing definitions for files used by Nintendo consoles
|
||||
|
||||
# Nintendo Switch NRO file
|
||||
0x10 string NRO0 Nintendo Switch NRO file
|
||||
>0x08 string HOMEBREW (Homebrew)
|
||||
>0x18 long x (Size %d)
|
||||
|
||||
# Nintendo Switch NSO file
|
||||
0x00 string NSO0 Nintendo Switch NSO file
|
||||
>0x04 long x Version %d
|
||||
>0x0C long x Flags %08x
|
||||
|
||||
# Nintendo Switch NCA file
|
||||
0x200 string NCA Nintendo Switch NCA file
|
||||
>0x203 byte x Version %c
|
||||
>0x204 byte 0 System NCA
|
||||
>0x204 byte 1 Gamecard NCA
|
||||
>0x210 quad x ProgramId %016llx
|
||||
@@ -19,6 +19,7 @@ add_library(${PROJECT_NAME} SHARED
|
||||
source/lang/en_US.cpp
|
||||
source/lang/de_DE.cpp
|
||||
source/lang/it_IT.cpp
|
||||
source/lang/zh_CN.cpp
|
||||
)
|
||||
|
||||
# Add additional include directories here #
|
||||
|
||||
@@ -28,9 +28,9 @@ namespace hex::plugin::builtin {
|
||||
|
||||
|
||||
if (result.has_value())
|
||||
return hex::format("#{0} = %{1}", input.data(), result.value());
|
||||
return hex::format("#{0} = {1}", input.data(), result.value());
|
||||
else
|
||||
return hex::format("#{0} = ???", input.data());
|
||||
return std::string("???");
|
||||
});
|
||||
|
||||
ContentRegistry::CommandPaletteCommands::add(
|
||||
|
||||
@@ -131,19 +131,19 @@ namespace hex::plugin::builtin {
|
||||
return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
|
||||
});
|
||||
|
||||
ContentRegistry::DataInspector::add("hex.builtin.inspector.string", 0, [](auto buffer, auto endian, auto style) {
|
||||
ContentRegistry::DataInspector::add("hex.builtin.inspector.string", 1, [](auto buffer, auto endian, auto style) {
|
||||
Region currSelection = { 0 };
|
||||
EventManager::post<QuerySelection>(currSelection);
|
||||
|
||||
constexpr static auto MaxStringLength = 32;
|
||||
|
||||
std::string stringBuffer(std::min<ssize_t>(MaxStringLength, currSelection.size), 0x00);
|
||||
SharedData::currentProvider->read(currSelection.address, stringBuffer.data(), stringBuffer.size());
|
||||
ImHexApi::Provider::get()->read(currSelection.address, stringBuffer.data(), stringBuffer.size());
|
||||
if (currSelection.size > MaxStringLength)
|
||||
stringBuffer += "...";
|
||||
|
||||
for (auto &c : stringBuffer)
|
||||
if (c < 0x20 || c == '\n' || c == '\r')
|
||||
if (c < 0x20)
|
||||
c = ' ';
|
||||
|
||||
|
||||
|
||||
@@ -380,7 +380,7 @@ namespace hex::plugin::builtin {
|
||||
std::vector<u8> data;
|
||||
data.resize(size);
|
||||
|
||||
SharedData::currentProvider->readRaw(address, data.data(), size);
|
||||
ImHexApi::Provider::get()->readRaw(address, data.data(), size);
|
||||
|
||||
this->setBufferOnOutput(2, data);
|
||||
}
|
||||
@@ -407,7 +407,7 @@ namespace hex::plugin::builtin {
|
||||
}) { }
|
||||
|
||||
void process() override {
|
||||
auto size = SharedData::currentProvider->getActualSize();
|
||||
auto size = ImHexApi::Provider::get()->getActualSize();
|
||||
|
||||
this->setIntegerOnOutput(0, size);
|
||||
}
|
||||
|
||||
@@ -2,17 +2,45 @@
|
||||
|
||||
#include <hex/helpers/shared_data.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/net.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
#include <hex/pattern_language/ast_node.hpp>
|
||||
#include <hex/pattern_language/token.hpp>
|
||||
#include <hex/pattern_language/log_console.hpp>
|
||||
#include <hex/pattern_language/evaluator.hpp>
|
||||
#include <hex/pattern_language/pattern_data.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/args.h>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
#define LITERAL_COMPARE(literal, cond) std::visit([&](auto &&literal) { return (cond) != 0; }, literal)
|
||||
#define AS_TYPE(type, value) ctx.template asType<type>(value)
|
||||
std::string format(pl::Evaluator *ctx, auto params) {
|
||||
auto format = pl::Token::literalToString(params[0], true);
|
||||
std::string message;
|
||||
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> formatArgs;
|
||||
|
||||
for (u32 i = 1; i < params.size(); i++) {
|
||||
auto ¶m = params[i];
|
||||
|
||||
std::visit(overloaded {
|
||||
[&](pl::PatternData* value) {
|
||||
formatArgs.push_back(value->toString(ctx->getProvider()));
|
||||
},
|
||||
[&](auto &&value) {
|
||||
formatArgs.push_back(value);
|
||||
}
|
||||
}, param);
|
||||
}
|
||||
|
||||
try {
|
||||
return fmt::vformat(format, formatArgs);
|
||||
} catch (fmt::format_error &error) {
|
||||
hex::pl::LogConsole::abortEvaluation(hex::format("format error: {}", error.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void registerPatternLanguageFunctions() {
|
||||
using namespace hex::pl;
|
||||
@@ -21,55 +49,37 @@ namespace hex::plugin::builtin {
|
||||
{
|
||||
|
||||
/* assert(condition, message) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert", 2, [](auto &ctx, auto params) {
|
||||
auto condition = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
|
||||
auto message = AS_TYPE(ASTNodeStringLiteral, params[1])->getString();
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto condition = Token::literalToBoolean(params[0]);
|
||||
auto message = std::get<std::string>(params[1]);
|
||||
|
||||
if (LITERAL_COMPARE(condition, condition == 0))
|
||||
ctx.getConsole().abortEvaluation(hex::format("assertion failed \"{0}\"", message.data()));
|
||||
if (!condition)
|
||||
LogConsole::abortEvaluation(hex::format("assertion failed \"{0}\"", message));
|
||||
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
/* assert_warn(condition, message) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert_warn", 2, [](auto ctx, auto params) {
|
||||
auto condition = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
|
||||
auto message = AS_TYPE(ASTNodeStringLiteral, params[1])->getString();
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert_warn", 2, [](auto *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto condition = Token::literalToBoolean(params[0]);
|
||||
auto message = std::get<std::string>(params[1]);
|
||||
|
||||
if (LITERAL_COMPARE(condition, condition == 0))
|
||||
ctx.getConsole().log(LogConsole::Level::Warning, hex::format("assertion failed \"{0}\"", message));
|
||||
if (!condition)
|
||||
ctx->getConsole().log(LogConsole::Level::Warning, hex::format("assertion failed \"{0}\"", message));
|
||||
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
/* print(values...) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStd, "print", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 0, [](auto &ctx, auto params) {
|
||||
std::string message;
|
||||
for (auto& param : params) {
|
||||
if (auto integerLiteral = dynamic_cast<ASTNodeIntegerLiteral*>(param); integerLiteral != nullptr) {
|
||||
std::visit([&](auto &&value) {
|
||||
using Type = std::remove_cvref_t<decltype(value)>;
|
||||
if constexpr (std::is_same_v<Type, char>)
|
||||
message += (char)value;
|
||||
else if constexpr (std::is_same_v<Type, bool>)
|
||||
message += value == 0 ? "false" : "true";
|
||||
else if constexpr (std::is_unsigned_v<Type>)
|
||||
message += std::to_string(static_cast<u64>(value));
|
||||
else if constexpr (std::is_signed_v<Type>)
|
||||
message += std::to_string(static_cast<s64>(value));
|
||||
else if constexpr (std::is_floating_point_v<Type>)
|
||||
message += std::to_string(value);
|
||||
else
|
||||
message += "< Custom Type >";
|
||||
}, integerLiteral->getValue());
|
||||
}
|
||||
else if (auto stringLiteral = dynamic_cast<ASTNodeStringLiteral*>(param); stringLiteral != nullptr)
|
||||
message += stringLiteral->getString();
|
||||
}
|
||||
/* print(format, args...) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStd, "print", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 0, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
ctx->getConsole().log(LogConsole::Level::Info, format(ctx, params));
|
||||
|
||||
ctx.getConsole().log(LogConsole::Level::Info, message);
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
return nullptr;
|
||||
/* format(format, args...) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStd, "format", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 0, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
return format(ctx, params);
|
||||
});
|
||||
|
||||
}
|
||||
@@ -78,141 +88,295 @@ namespace hex::plugin::builtin {
|
||||
{
|
||||
|
||||
/* align_to(alignment, value) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "align_to", 2, [](auto &ctx, auto params) -> ASTNode* {
|
||||
auto alignment = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
|
||||
auto value = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue();
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "align_to", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto alignment = Token::literalToUnsigned(params[0]);
|
||||
auto value = Token::literalToUnsigned(params[1]);
|
||||
|
||||
auto result = std::visit([](auto &&alignment, auto &&value) {
|
||||
u64 remainder = u64(value) % u64(alignment);
|
||||
return remainder != 0 ? u64(value) + (u64(alignment) - remainder) : u64(value);
|
||||
}, alignment, value);
|
||||
u128 remainder = value % alignment;
|
||||
|
||||
return new ASTNodeIntegerLiteral(u64(result));
|
||||
return remainder != 0 ? value + (alignment - remainder) : value;
|
||||
});
|
||||
|
||||
/* base_address() */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "base_address", ContentRegistry::PatternLanguageFunctions::NoParameters, [](auto &ctx, auto params) -> ASTNode* {
|
||||
return new ASTNodeIntegerLiteral(u64(SharedData::currentProvider->getBaseAddress()));
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "base_address", ContentRegistry::PatternLanguageFunctions::NoParameters, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
return u128(ctx->getProvider()->getBaseAddress());
|
||||
});
|
||||
|
||||
/* size() */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "size", ContentRegistry::PatternLanguageFunctions::NoParameters, [](auto &ctx, auto params) -> ASTNode* {
|
||||
return new ASTNodeIntegerLiteral(u64(SharedData::currentProvider->getActualSize()));
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "size", ContentRegistry::PatternLanguageFunctions::NoParameters, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
return u128(ctx->getProvider()->getActualSize());
|
||||
});
|
||||
|
||||
/* find_sequence(occurrence_index, bytes...) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "find_sequence", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 1, [](auto &ctx, auto params) {
|
||||
auto& occurrenceIndex = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "find_sequence", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto occurrenceIndex = Token::literalToUnsigned(params[0]);
|
||||
|
||||
std::vector<u8> sequence;
|
||||
for (u32 i = 1; i < params.size(); i++) {
|
||||
sequence.push_back(std::visit([&](auto &&value) -> u8 {
|
||||
if (value <= 0xFF)
|
||||
return value;
|
||||
else
|
||||
ctx.getConsole().abortEvaluation("sequence bytes need to fit into 1 byte");
|
||||
}, AS_TYPE(ASTNodeIntegerLiteral, params[i])->getValue()));
|
||||
auto byte = Token::literalToUnsigned(params[i]);
|
||||
|
||||
if (byte > 0xFF)
|
||||
LogConsole::abortEvaluation(hex::format("byte #{} value out of range: {} > 0xFF", i, u64(byte)));
|
||||
|
||||
sequence.push_back(u8(byte & 0xFF));
|
||||
}
|
||||
|
||||
std::vector<u8> bytes(sequence.size(), 0x00);
|
||||
u32 occurrences = 0;
|
||||
for (u64 offset = 0; offset < SharedData::currentProvider->getSize() - sequence.size(); offset++) {
|
||||
SharedData::currentProvider->read(offset, bytes.data(), bytes.size());
|
||||
for (u64 offset = 0; offset < ctx->getProvider()->getSize() - sequence.size(); offset++) {
|
||||
ctx->getProvider()->read(offset, bytes.data(), bytes.size());
|
||||
|
||||
if (bytes == sequence) {
|
||||
if (LITERAL_COMPARE(occurrenceIndex, occurrences < occurrenceIndex)) {
|
||||
if (occurrences < occurrenceIndex) {
|
||||
occurrences++;
|
||||
continue;
|
||||
}
|
||||
|
||||
return new ASTNodeIntegerLiteral(offset);
|
||||
return u128(offset);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.getConsole().abortEvaluation("failed to find sequence");
|
||||
LogConsole::abortEvaluation("failed to find sequence");
|
||||
});
|
||||
|
||||
/* read_unsigned(address, size) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "read_unsigned", 2, [](auto &ctx, auto params) {
|
||||
auto address = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
|
||||
auto size = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue();
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "read_unsigned", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto address = Token::literalToUnsigned(params[0]);
|
||||
auto size = Token::literalToUnsigned(params[1]);
|
||||
|
||||
if (LITERAL_COMPARE(address, address >= SharedData::currentProvider->getActualSize()))
|
||||
ctx.getConsole().abortEvaluation("address out of range");
|
||||
if (size > 16)
|
||||
LogConsole::abortEvaluation("read size out of range");
|
||||
|
||||
return std::visit([&](auto &&address, auto &&size) {
|
||||
if (size <= 0 || size > 16)
|
||||
ctx.getConsole().abortEvaluation("invalid read size");
|
||||
u128 result = 0;
|
||||
ctx->getProvider()->read(address, &result, size);
|
||||
|
||||
u8 value[(u8)size];
|
||||
SharedData::currentProvider->read(address, value, size);
|
||||
|
||||
switch ((u8)size) {
|
||||
case 1: return new ASTNodeIntegerLiteral(*reinterpret_cast<u8*>(value));
|
||||
case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast<u16*>(value));
|
||||
case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast<u32*>(value));
|
||||
case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast<u64*>(value));
|
||||
case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast<u128*>(value));
|
||||
default: ctx.getConsole().abortEvaluation("invalid read size");
|
||||
}
|
||||
}, address, size);
|
||||
return result;
|
||||
});
|
||||
|
||||
/* read_signed(address, size) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "read_signed", 2, [](auto &ctx, auto params) {
|
||||
auto address = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
|
||||
auto size = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue();
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "read_signed", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto address = Token::literalToUnsigned(params[0]);
|
||||
auto size = Token::literalToUnsigned(params[1]);
|
||||
|
||||
if (LITERAL_COMPARE(address, address >= SharedData::currentProvider->getActualSize()))
|
||||
ctx.getConsole().abortEvaluation("address out of range");
|
||||
if (size > 16)
|
||||
LogConsole::abortEvaluation("read size out of range");
|
||||
|
||||
return std::visit([&](auto &&address, auto &&size) {
|
||||
if (size <= 0 || size > 16)
|
||||
ctx.getConsole().abortEvaluation("invalid read size");
|
||||
s128 value;
|
||||
ctx->getProvider()->read(address, &value, size);
|
||||
return hex::signExtend(size * 8, value);
|
||||
});
|
||||
|
||||
u8 value[(u8)size];
|
||||
SharedData::currentProvider->read(address, value, size);
|
||||
/* read_string(address, size) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "read_string", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto address = Token::literalToUnsigned(params[0]);
|
||||
auto size = Token::literalToUnsigned(params[1]);
|
||||
|
||||
switch ((u8)size) {
|
||||
case 1: return new ASTNodeIntegerLiteral(*reinterpret_cast<s8*>(value));
|
||||
case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast<s16*>(value));
|
||||
case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast<s32*>(value));
|
||||
case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast<s64*>(value));
|
||||
case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast<s128*>(value));
|
||||
default: ctx.getConsole().abortEvaluation("invalid read size");
|
||||
}
|
||||
}, address, size);
|
||||
std::string result(size, '\x00');
|
||||
ctx->getProvider()->read(address, result.data(), size);
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
ContentRegistry::PatternLanguageFunctions::Namespace nsStdStr = { "std", "str" };
|
||||
ContentRegistry::PatternLanguageFunctions::Namespace nsStdString = { "std", "string" };
|
||||
{
|
||||
/* length(string) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "length", 1, [](auto &ctx, auto params) {
|
||||
auto string = AS_TYPE(ASTNodeStringLiteral, params[1])->getString();
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "length", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto string = Token::literalToString(params[0], false);
|
||||
|
||||
return new ASTNodeIntegerLiteral(u32(string.length()));
|
||||
return u128(string.length());
|
||||
});
|
||||
|
||||
/* at(string, index) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "at", 2, [](auto &ctx, auto params) {
|
||||
auto string = AS_TYPE(ASTNodeStringLiteral, params[0])->getString();
|
||||
auto index = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue();
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "at", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto string = Token::literalToString(params[0], false);
|
||||
auto index = Token::literalToSigned(params[1]);
|
||||
|
||||
if (LITERAL_COMPARE(index, index >= string.length() || index < 0))
|
||||
ctx.getConsole().abortEvaluation("character index out of bounds");
|
||||
#if defined(OS_MACOS)
|
||||
const auto signIndex = index >> (sizeof(index) * 8 - 1);
|
||||
const auto absIndex = (index ^ signIndex) - signIndex;
|
||||
#else
|
||||
const auto absIndex = std::abs(index);
|
||||
#endif
|
||||
|
||||
return std::visit([&](auto &&value) { return new ASTNodeIntegerLiteral(char(string[u32(value)])); }, index);
|
||||
if (absIndex > string.length())
|
||||
LogConsole::abortEvaluation("character index out of range");
|
||||
|
||||
if (index >= 0)
|
||||
return char(string[index]);
|
||||
else
|
||||
return char(string[string.length() - -index]);
|
||||
});
|
||||
|
||||
/* compare(left, right) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "compare", 2, [](auto &ctx, auto params) {
|
||||
auto left = AS_TYPE(ASTNodeStringLiteral, params[0])->getString();
|
||||
auto right = AS_TYPE(ASTNodeStringLiteral, params[1])->getString();
|
||||
/* substr(string, pos, count) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "substr", 3, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto string = Token::literalToString(params[0], false);
|
||||
auto pos = Token::literalToUnsigned(params[1]);
|
||||
auto size = Token::literalToUnsigned(params[2]);
|
||||
|
||||
return new ASTNodeIntegerLiteral(bool(left == right));
|
||||
if (pos > string.length())
|
||||
LogConsole::abortEvaluation("character index out of range");
|
||||
|
||||
return string.substr(pos, size);
|
||||
});
|
||||
|
||||
/* parse_int(string, base) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "parse_int", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto string = Token::literalToString(params[0], false);
|
||||
auto base = Token::literalToUnsigned(params[1]);
|
||||
|
||||
return s128(std::strtoll(string.c_str(), nullptr, base));
|
||||
});
|
||||
|
||||
/* parse_float(string) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "parse_float", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto string = Token::literalToString(params[0], false);
|
||||
|
||||
return double(std::strtod(string.c_str(), nullptr));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
ContentRegistry::PatternLanguageFunctions::Namespace nsStdHttp = { "std", "http" };
|
||||
{
|
||||
/* get(url) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdHttp, "get", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
const auto url = Token::literalToString(params[0], false);
|
||||
|
||||
hex::Net net;
|
||||
return net.getString(url).get().body;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
ContentRegistry::PatternLanguageFunctions::Namespace nsStdFile = { "std", "file" };
|
||||
{
|
||||
|
||||
static u32 fileCounter = 0;
|
||||
static std::map<u32, File> openFiles;
|
||||
|
||||
/* open(path, mode) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdFile, "open", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
const auto path = Token::literalToString(params[0], false);
|
||||
const auto modeEnum = Token::literalToUnsigned(params[1]);
|
||||
|
||||
File::Mode mode;
|
||||
switch (modeEnum) {
|
||||
case 1: mode = File::Mode::Read; break;
|
||||
case 2: mode = File::Mode::Write; break;
|
||||
case 3: mode = File::Mode::Create; break;
|
||||
default:
|
||||
LogConsole::abortEvaluation("invalid file open mode");
|
||||
}
|
||||
|
||||
auto file = File(path, mode);
|
||||
|
||||
if (!file.isValid())
|
||||
LogConsole::abortEvaluation(hex::format("failed to open file {}", path));
|
||||
|
||||
fileCounter++;
|
||||
openFiles.emplace(std::pair{ fileCounter, std::move(file) });
|
||||
|
||||
return u128(fileCounter);
|
||||
});
|
||||
|
||||
/* close(file) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdFile, "close", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
const auto file = Token::literalToUnsigned(params[0]);
|
||||
|
||||
if (!openFiles.contains(file))
|
||||
LogConsole::abortEvaluation("failed to access invalid file");
|
||||
|
||||
openFiles.erase(file);
|
||||
|
||||
return { };
|
||||
});
|
||||
|
||||
/* read(file, size) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdFile, "read", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
const auto file = Token::literalToUnsigned(params[0]);
|
||||
const auto size = Token::literalToUnsigned(params[1]);
|
||||
|
||||
if (!openFiles.contains(file))
|
||||
LogConsole::abortEvaluation("failed to access invalid file");
|
||||
|
||||
return openFiles[file].readString(size);
|
||||
});
|
||||
|
||||
/* write(file, data) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdFile, "write", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
const auto file = Token::literalToUnsigned(params[0]);
|
||||
const auto data = Token::literalToString(params[1], true);
|
||||
|
||||
if (!openFiles.contains(file))
|
||||
LogConsole::abortEvaluation("failed to access invalid file");
|
||||
|
||||
openFiles[file].write(data);
|
||||
|
||||
return { };
|
||||
});
|
||||
|
||||
/* seek(file, offset) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdFile, "seek", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
const auto file = Token::literalToUnsigned(params[0]);
|
||||
const auto offset = Token::literalToUnsigned(params[1]);
|
||||
|
||||
if (!openFiles.contains(file))
|
||||
LogConsole::abortEvaluation("failed to access invalid file");
|
||||
|
||||
openFiles[file].seek(offset);
|
||||
|
||||
return { };
|
||||
});
|
||||
|
||||
/* size(file) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdFile, "size", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
const auto file = Token::literalToUnsigned(params[0]);
|
||||
|
||||
if (!openFiles.contains(file))
|
||||
LogConsole::abortEvaluation("failed to access invalid file");
|
||||
|
||||
return u128(openFiles[file].getSize());
|
||||
});
|
||||
|
||||
/* resize(file, size) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdFile, "resize", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
const auto file = Token::literalToUnsigned(params[0]);
|
||||
const auto size = Token::literalToUnsigned(params[1]);
|
||||
|
||||
if (!openFiles.contains(file))
|
||||
LogConsole::abortEvaluation("failed to access invalid file");
|
||||
|
||||
openFiles[file].setSize(size);
|
||||
|
||||
return { };
|
||||
});
|
||||
|
||||
/* flush(file) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdFile, "flush", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
const auto file = Token::literalToUnsigned(params[0]);
|
||||
|
||||
if (!openFiles.contains(file))
|
||||
LogConsole::abortEvaluation("failed to access invalid file");
|
||||
|
||||
openFiles[file].flush();
|
||||
|
||||
return { };
|
||||
});
|
||||
|
||||
/* remove(file) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdFile, "remove", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
const auto file = Token::literalToUnsigned(params[0]);
|
||||
|
||||
if (!openFiles.contains(file))
|
||||
LogConsole::abortEvaluation("failed to access invalid file");
|
||||
|
||||
openFiles[file].remove();
|
||||
|
||||
return { };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,18 @@ namespace hex::plugin::builtin {
|
||||
/* General */
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.show_tips", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = setting.is_number() ? static_cast<int>(setting) : 1;
|
||||
static bool enabled = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
@@ -28,9 +39,10 @@ namespace hex::plugin::builtin {
|
||||
/* Interface */
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", 0, [](auto name, nlohmann::json &setting) {
|
||||
static int selection = setting.is_number() ? static_cast<int>(setting) : 0;
|
||||
static int selection = static_cast<int>(setting);
|
||||
|
||||
const char* themes[] = {
|
||||
"hex.builtin.setting.interface.color.system"_lang,
|
||||
"hex.builtin.setting.interface.color.dark"_lang,
|
||||
"hex.builtin.setting.interface.color.light"_lang,
|
||||
"hex.builtin.setting.interface.color.classic"_lang
|
||||
@@ -45,7 +57,7 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling", 0, [](auto name, nlohmann::json &setting) {
|
||||
static int selection = setting.is_number() ? static_cast<int>(setting) : 0;
|
||||
static int selection = static_cast<int>(setting);
|
||||
|
||||
const char* scaling[] = {
|
||||
"hex.builtin.setting.interface.scaling.native"_lang,
|
||||
@@ -82,6 +94,8 @@ namespace hex::plugin::builtin {
|
||||
|
||||
static auto languageNames = [&]() {
|
||||
std::vector<const char*> result;
|
||||
result.reserve(languages.size());
|
||||
|
||||
for (auto &[languageCode, languageName] : languages)
|
||||
result.push_back(languageName.c_str());
|
||||
|
||||
@@ -107,9 +121,11 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.fps", 60, [](auto name, nlohmann::json &setting) {
|
||||
static int fps = setting.is_number() ? static_cast<int>(setting) : 60;
|
||||
static int fps = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &fps, 15, 60)) {
|
||||
auto format = fps > 200 ? "hex.builtin.setting.interface.fps.unlocked"_lang : "%d FPS";
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &fps, 15, 201, format, ImGuiSliderFlags_AlwaysClamp)) {
|
||||
setting = fps;
|
||||
return true;
|
||||
}
|
||||
@@ -118,7 +134,7 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.highlight_alpha", 0x80, [](auto name, nlohmann::json &setting) {
|
||||
static int alpha = setting.is_number() ? static_cast<int>(setting) : 0x80;
|
||||
static int alpha = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &alpha, 0x00, 0xFF)) {
|
||||
setting = alpha;
|
||||
@@ -128,6 +144,83 @@ namespace hex::plugin::builtin {
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.column_count", 16, [](auto name, nlohmann::json &setting) {
|
||||
static int columns = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &columns, 1, 32)) {
|
||||
setting = columns;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.hexii", 0, [](auto name, nlohmann::json &setting) {
|
||||
static bool hexii = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &hexii)) {
|
||||
setting = static_cast<int>(hexii);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.ascii", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool ascii = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &ascii)) {
|
||||
setting = static_cast<int>(ascii);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.advanced_decoding", 0, [](auto name, nlohmann::json &setting) {
|
||||
static bool advancedDecoding = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &advancedDecoding)) {
|
||||
setting = static_cast<int>(advancedDecoding);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.grey_zeros", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool greyZeros = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &greyZeros)) {
|
||||
setting = static_cast<int>(greyZeros);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.uppercase_hex", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool upperCaseHex = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &upperCaseHex)) {
|
||||
setting = static_cast<int>(upperCaseHex);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.extra_info", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool extraInfos = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &extraInfos)) {
|
||||
setting = static_cast<int>(extraInfos);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,17 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
|
||||
#include <hex/helpers/net.hpp>
|
||||
#include <hex/helpers/shared_data.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/literals.hpp>
|
||||
|
||||
#include <regex>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
|
||||
#include <llvm/Demangle/Demangle.h>
|
||||
#include "math_evaluator.hpp"
|
||||
@@ -23,6 +28,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
using namespace std::literals::chrono_literals;
|
||||
using namespace hex::literals;
|
||||
|
||||
int updateStringSizeCallback(ImGuiInputTextCallbackData *data) {
|
||||
auto &mathInput = *static_cast<std::string*>(data->UserData);
|
||||
@@ -97,24 +103,22 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
void drawRegexReplacer() {
|
||||
static std::vector<char> regexInput(0xF'FFFF, 0x00);;
|
||||
static std::vector<char> regexPattern(0xF'FFFF, 0x00);;
|
||||
static std::vector<char> replacePattern(0xF'FFFF, 0x00);;
|
||||
static std::string regexOutput(0xF'FFFF, 0x00);;
|
||||
static auto regexInput = []{ std::string s; s.reserve(0xFFF); return s; }();
|
||||
static auto regexPattern = []{ std::string s; s.reserve(0xFFF); return s; }();
|
||||
static auto replacePattern = []{ std::string s; s.reserve(0xFFF); return s; }();
|
||||
static auto regexOutput = []{ std::string s; s.reserve(0xFFF); return s; }();
|
||||
|
||||
bool shouldInvalidate;
|
||||
bool changed1 = ImGui::InputText("hex.builtin.tools.regex_replacer.pattern"_lang, regexPattern.data(), regexPattern.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, ®exPattern);
|
||||
bool changed2 = ImGui::InputText("hex.builtin.tools.regex_replacer.replace"_lang, replacePattern.data(), replacePattern.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &replacePattern);
|
||||
bool changed3 = ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.input"_lang, regexInput.data(), regexInput.capacity(), ImVec2(0, 0), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, ®exInput);
|
||||
|
||||
shouldInvalidate = ImGui::InputText("hex.builtin.tools.regex_replacer.pattern"_lang, regexPattern.data(), regexPattern.size());
|
||||
shouldInvalidate = ImGui::InputText("hex.builtin.tools.regex_replacer.replace"_lang, replacePattern.data(), replacePattern.size()) || shouldInvalidate;
|
||||
shouldInvalidate = ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.input"_lang, regexInput.data(), regexInput.size()) || shouldInvalidate;
|
||||
|
||||
if (shouldInvalidate) {
|
||||
if (changed1 || changed2 || changed3) {
|
||||
try {
|
||||
regexOutput = std::regex_replace(regexInput.data(), std::regex(regexPattern.data()), replacePattern.data());
|
||||
} catch (std::regex_error&) {}
|
||||
}
|
||||
|
||||
ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.input"_lang, regexOutput.data(), regexOutput.size(), ImVec2(0, 0), ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.output"_lang, regexOutput.data(), regexOutput.size(), ImVec2(0, 0), ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::NewLine();
|
||||
}
|
||||
|
||||
@@ -158,8 +162,8 @@ namespace hex::plugin::builtin {
|
||||
evaluator.setFunction("read", [](auto args) -> std::optional<long double> {
|
||||
u8 value = 0;
|
||||
|
||||
auto provider = SharedData::currentProvider;
|
||||
if (provider == nullptr || !provider->isReadable() || args[0] >= provider->getActualSize())
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
if (!ImHexApi::Provider::isValid() || !provider->isReadable() || args[0] >= provider->getActualSize())
|
||||
return { };
|
||||
|
||||
provider->read(args[0], &value, sizeof(u8));
|
||||
@@ -168,8 +172,8 @@ namespace hex::plugin::builtin {
|
||||
}, 1, 1);
|
||||
|
||||
evaluator.setFunction("write", [](auto args) -> std::optional<long double> {
|
||||
auto provider = SharedData::currentProvider;
|
||||
if (provider == nullptr || !provider->isWritable() || args[0] >= provider->getActualSize())
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
if (!ImHexApi::Provider::isValid() || !provider->isWritable() || args[0] >= provider->getActualSize())
|
||||
return { };
|
||||
|
||||
if (args[1] > 0xFF)
|
||||
@@ -667,6 +671,372 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void drawFileToolShredder() {
|
||||
static bool shredding = false;
|
||||
static auto selectedFile = []{ std::string s; s.reserve(0x1000); return s; }();
|
||||
static bool fastMode = false;
|
||||
|
||||
ImGui::TextUnformatted("hex.builtin.tools.file_tools.shredder.warning"_lang);
|
||||
ImGui::NewLine();
|
||||
|
||||
if (ImGui::BeginChild("settings", { 0, ImGui::GetTextLineHeightWithSpacing() * 4 }, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||
ImGui::BeginDisabled(shredding);
|
||||
{
|
||||
ImGui::TextUnformatted("hex.builtin.tools.file_tools.shredder.input"_lang);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("##path", selectedFile.data(), selectedFile.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &selectedFile);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("...")) {
|
||||
hex::openFileBrowser("hex.builtin.tools.file_tools.shredder.picker"_lang, DialogMode::Open, {}, [](const std::string &path) {
|
||||
selectedFile = path;
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::Checkbox("hex.builtin.tools.file_tools.shredder.fast"_lang, &fastMode);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
if (shredding)
|
||||
ImGui::TextSpinner("hex.builtin.tools.file_tools.shredder.shredding"_lang);
|
||||
else {
|
||||
ImGui::BeginDisabled(selectedFile.empty());
|
||||
{
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.shredder.shred"_lang)) {
|
||||
shredding = true;
|
||||
|
||||
std::thread([]{
|
||||
ON_SCOPE_EXIT { shredding = false; selectedFile.clear(); };
|
||||
File file(selectedFile, File::Mode::Write);
|
||||
|
||||
if (!file.isValid()) {
|
||||
View::showErrorPopup("hex.builtin.tools.file_tools.shredder.error.open"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::array<u8, 3>> overwritePattern;
|
||||
if (fastMode) {
|
||||
/* Should be sufficient for modern disks */
|
||||
overwritePattern.push_back({ 0x00, 0x00, 0x00 });
|
||||
overwritePattern.push_back({ 0xFF, 0xFF, 0xFF });
|
||||
}
|
||||
else {
|
||||
/* Gutmann's method. Secure for magnetic storage */
|
||||
std::random_device rd;
|
||||
std::uniform_int_distribution<u8> dist(0x00, 0xFF);
|
||||
|
||||
/* Fill fixed patterns */
|
||||
overwritePattern = {
|
||||
{}, {}, {}, {},
|
||||
{ 0x55, 0x55, 0x55 }, { 0xAA, 0xAA, 0xAA }, { 0x92, 0x49, 0x24 }, { 0x49, 0x24, 0x92 },
|
||||
{ 0x24, 0x92, 0x49 }, { 0x00, 0x00, 0x00 }, { 0x11, 0x11, 0x11 }, { 0x22, 0x22, 0x22 },
|
||||
{ 0x33, 0x33, 0x44 }, { 0x55, 0x55, 0x55 }, { 0x66, 0x66, 0x66 }, { 0x77, 0x77, 0x77 },
|
||||
{ 0x88, 0x88, 0x88 }, { 0x99, 0x99, 0x99 }, { 0xAA, 0xAA, 0xAA }, { 0xBB, 0xBB, 0xBB },
|
||||
{ 0xCC, 0xCC, 0xCC }, { 0xDD, 0xDD, 0xDD }, { 0xEE, 0xEE, 0xEE }, { 0xFF, 0xFF, 0xFF },
|
||||
{ 0x92, 0x49, 0x24 }, { 0x49, 0x24, 0x92 }, { 0x24, 0x92, 0x49 }, { 0x6D, 0xB6, 0xDB },
|
||||
{ 0xB6, 0xDB, 0x6D }, { 0xBD, 0x6D, 0xB6 },
|
||||
{}, {}, {}, {}
|
||||
};
|
||||
|
||||
/* Fill random patterns */
|
||||
for (u8 i = 0; i < 4; i++)
|
||||
overwritePattern[i] = { dist(rd), dist(rd), dist(rd) };
|
||||
for (u8 i = 0; i < 4; i++)
|
||||
overwritePattern[overwritePattern.size() - 1 - i] = { dist(rd), dist(rd), dist(rd) };
|
||||
}
|
||||
|
||||
size_t fileSize = file.getSize();
|
||||
for (const auto &pattern : overwritePattern) {
|
||||
for (u64 offset = 0; offset < fileSize; offset += 3) {
|
||||
file.write(pattern.data(), std::min<u64>(pattern.size(), fileSize - offset));
|
||||
}
|
||||
|
||||
file.flush();
|
||||
}
|
||||
|
||||
file.remove();
|
||||
|
||||
View::showMessagePopup("hex.builtin.tools.file_tools.shredder.success"_lang);
|
||||
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
void drawFileToolSplitter() {
|
||||
std::array sizeText = {
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.zip100"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.zip200"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.cdrom650"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.cdrom700"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.fat32"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.custom"_lang
|
||||
};
|
||||
std::array<u64, sizeText.size()> sizes = {
|
||||
1200_KiB,
|
||||
1400_KiB,
|
||||
100_MiB,
|
||||
200_MiB,
|
||||
650_MiB,
|
||||
700_MiB,
|
||||
4_GiB,
|
||||
1
|
||||
};
|
||||
|
||||
static bool splitting = false;
|
||||
static auto selectedFile = []{ std::string s; s.reserve(0x1000); return s; }();
|
||||
static auto baseOutputPath = []{ std::string s; s.reserve(0x1000); return s; }();
|
||||
static u64 splitSize = sizes[0];
|
||||
static int selectedItem = 0;
|
||||
|
||||
if (ImGui::BeginChild("split_settings", { 0, ImGui::GetTextLineHeightWithSpacing() * 7 }, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||
ImGui::BeginDisabled(splitting);
|
||||
{
|
||||
ImGui::TextUnformatted("hex.builtin.tools.file_tools.splitter.input"_lang);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("##path", selectedFile.data(), selectedFile.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &selectedFile);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("...##input")) {
|
||||
hex::openFileBrowser("hex.builtin.tools.file_tools.splitter.picker.input"_lang, DialogMode::Open, {}, [](const std::string &path) {
|
||||
selectedFile = path;
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted("hex.builtin.tools.file_tools.splitter.output"_lang);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("##base_path", baseOutputPath.data(), baseOutputPath.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &baseOutputPath);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("...##output")) {
|
||||
hex::openFileBrowser("hex.builtin.tools.file_tools.splitter.picker.output"_lang, DialogMode::Save, {}, [](const std::string &path) {
|
||||
baseOutputPath = path;
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Combo("###part_size", &selectedItem, sizeText.data(), sizeText.size())) {
|
||||
splitSize = sizes[selectedItem];
|
||||
}
|
||||
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::BeginDisabled(splitting || selectedItem != sizes.size() - 1);
|
||||
{
|
||||
ImGui::InputScalar("###custom_size", ImGuiDataType_U64, &splitSize);
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted("Bytes");
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::BeginDisabled(selectedFile.empty() || baseOutputPath.empty() || splitSize == 0);
|
||||
{
|
||||
if (splitting)
|
||||
ImGui::TextSpinner("hex.builtin.tools.file_tools.splitter.splitting"_lang);
|
||||
else {
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.splitter.split"_lang)) {
|
||||
splitting = true;
|
||||
|
||||
std::thread([]{
|
||||
ON_SCOPE_EXIT { splitting = false; selectedFile.clear(); baseOutputPath.clear(); };
|
||||
File file(selectedFile, File::Mode::Read);
|
||||
|
||||
if (!file.isValid()) {
|
||||
View::showErrorPopup("hex.builtin.tools.file_tools.splitter.error.open"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.getSize() < splitSize) {
|
||||
View::showErrorPopup("hex.builtin.tools.file_tools.splitter.error.size"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 index = 1;
|
||||
for (u64 offset = 0; offset < file.getSize(); offset += splitSize) {
|
||||
File partFile(baseOutputPath + hex::format(".{:05}", index), File::Mode::Create);
|
||||
|
||||
if (!partFile.isValid()) {
|
||||
View::showErrorPopup(hex::format("hex.builtin.tools.file_tools.splitter.error.create"_lang, index));
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr auto BufferSize = 0xFF'FFFF;
|
||||
for (u64 partOffset = 0; partOffset < splitSize; partOffset += BufferSize) {
|
||||
partFile.write(file.readBytes(std::min<u64>(BufferSize, splitSize - partOffset)));
|
||||
partFile.flush();
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
View::showMessagePopup("hex.builtin.tools.file_tools.splitter.success"_lang);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
void drawFileToolCombiner() {
|
||||
static bool combining = false;
|
||||
static std::vector<std::string> files;
|
||||
static auto outputPath = []{ std::string s; s.reserve(0x1000); return s; }();
|
||||
static s32 selectedIndex;
|
||||
|
||||
if (ImGui::BeginTable("files_table", 2, ImGuiTableFlags_SizingStretchProp)) {
|
||||
ImGui::TableSetupColumn("file list", ImGuiTableColumnFlags_NoHeaderLabel, 10);
|
||||
ImGui::TableSetupColumn("buttons", ImGuiTableColumnFlags_NoHeaderLabel, 1);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (ImGui::BeginListBox("##files", { -FLT_MIN, 10 * ImGui::GetTextLineHeightWithSpacing() })) {
|
||||
|
||||
s32 index = 0;
|
||||
for (auto &file : files) {
|
||||
if (ImGui::Selectable(std::filesystem::path(file).filename().string().c_str(), index == selectedIndex))
|
||||
selectedIndex = index;
|
||||
index++;
|
||||
}
|
||||
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::BeginDisabled(selectedIndex <= 0) ;
|
||||
{
|
||||
if (ImGui::ArrowButton("move_up", ImGuiDir_Up)) {
|
||||
std::iter_swap(files.begin() + selectedIndex, files.begin() + selectedIndex - 1);
|
||||
selectedIndex--;
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::BeginDisabled(files.empty() || selectedIndex >= files.size() - 1) ;
|
||||
{
|
||||
if (ImGui::ArrowButton("move_down", ImGuiDir_Down)) {
|
||||
std::iter_swap(files.begin() + selectedIndex, files.begin() + selectedIndex + 1);
|
||||
selectedIndex++;
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::BeginDisabled(combining);
|
||||
{
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.add"_lang)) {
|
||||
hex::openFileBrowser("hex.builtin.tools.file_tools.combiner.add.picker"_lang, DialogMode::Open, {}, [](const std::string &path) {
|
||||
files.push_back(path);
|
||||
});
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.delete"_lang)) {
|
||||
files.erase(files.begin() + selectedIndex);
|
||||
selectedIndex--;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.clear"_lang)) {
|
||||
files.clear();
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::BeginDisabled(combining);
|
||||
{
|
||||
ImGui::TextUnformatted("hex.builtin.tools.file_tools.combiner.output"_lang);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("##output_path", outputPath.data(), outputPath.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &outputPath);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("...")) {
|
||||
hex::openFileBrowser("hex.builtin.tools.file_tools.combiner.output.picker"_lang, DialogMode::Save, {}, [](const std::string &path) {
|
||||
outputPath = path;
|
||||
});
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::BeginDisabled(files.empty() || outputPath.empty());
|
||||
{
|
||||
if (combining)
|
||||
ImGui::TextSpinner("hex.builtin.tools.file_tools.combiner.combining"_lang);
|
||||
else {
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.combine"_lang)) {
|
||||
combining = true;
|
||||
|
||||
std::thread([]{
|
||||
ON_SCOPE_EXIT { combining = false; };
|
||||
|
||||
File output(outputPath, File::Mode::Create);
|
||||
|
||||
if (!output.isValid()) {
|
||||
View::showErrorPopup("hex.builtin.tools.file_tools.combiner.error.open_output"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &file : files) {
|
||||
File input(file, File::Mode::Read);
|
||||
|
||||
if (!input.isValid()) {
|
||||
View::showErrorPopup(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, std::filesystem::path(file).filename().string()));
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr auto BufferSize = 0xFF'FFFF;
|
||||
auto inputSize = input.getSize();
|
||||
for (u64 inputOffset = 0; inputOffset < inputSize; inputOffset += BufferSize) {
|
||||
output.write(input.readBytes(std::min<u64>(BufferSize, inputSize - inputOffset)));
|
||||
output.flush();
|
||||
}
|
||||
}
|
||||
|
||||
files.clear();
|
||||
selectedIndex = 0;
|
||||
outputPath.clear();
|
||||
|
||||
View::showMessagePopup("hex.builtin.tools.file_tools.combiner.success"_lang);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
}
|
||||
|
||||
void drawFileTools() {
|
||||
|
||||
if (ImGui::BeginTabBar("file_tools_tabs")) {
|
||||
|
||||
if (ImGui::BeginTabItem("hex.builtin.tools.file_tools.shredder"_lang)) {
|
||||
drawFileToolShredder();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("hex.builtin.tools.file_tools.splitter"_lang)) {
|
||||
drawFileToolSplitter();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("hex.builtin.tools.file_tools.combiner"_lang)) {
|
||||
drawFileToolCombiner();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
}
|
||||
|
||||
void registerToolEntries() {
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.demangler", drawDemangler);
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.ascii_table", drawASCIITable);
|
||||
@@ -677,6 +1047,7 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.permissions", drawPermissionsCalculator);
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.file_uploader", drawFileUploader);
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.wiki_explain", drawWikiExplainer);
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.file_tools", drawFileTools);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,38 +19,36 @@ namespace hex::plugin::builtin {
|
||||
framerate = 1.0F / ImGui::GetIO().DeltaTime;
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted(hex::format("FPS {0:.2f}", framerate).c_str());
|
||||
ImGui::TextUnformatted(hex::format("FPS {0:2}.{1:02}", u32(framerate), u32(framerate * 100) % 100).c_str());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void addToolbarItems() {
|
||||
ContentRegistry::Interface::addToolbarItem([] {
|
||||
const static auto buttonSize = ImVec2(ImGui::GetCurrentWindow()->MenuBarHeight(), ImGui::GetCurrentWindow()->MenuBarHeight());
|
||||
|
||||
auto provider = SharedData::currentProvider;
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
// Undo
|
||||
ImGui::Disabled([&provider] {
|
||||
if (ImGui::ToolBarButton(ICON_VS_DISCARD, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize))
|
||||
if (ImGui::ToolBarButton(ICON_VS_DISCARD, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
provider->undo();
|
||||
}, provider == nullptr || !provider->canUndo());
|
||||
}, !ImHexApi::Provider::isValid() || !provider->canUndo());
|
||||
|
||||
// Redo
|
||||
ImGui::Disabled([&provider] {
|
||||
if (ImGui::ToolBarButton(ICON_VS_REDO, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize))
|
||||
if (ImGui::ToolBarButton(ICON_VS_REDO, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
provider->redo();
|
||||
}, provider == nullptr || !provider->canRedo());
|
||||
}, !ImHexApi::Provider::isValid() || !provider->canRedo());
|
||||
|
||||
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
|
||||
// Create new file
|
||||
if (ImGui::ToolBarButton(ICON_VS_FILE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGray), buttonSize))
|
||||
if (ImGui::ToolBarButton(ICON_VS_FILE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGray)))
|
||||
EventManager::post<RequestOpenWindow>("Create File");
|
||||
|
||||
// Open file
|
||||
if (ImGui::ToolBarButton(ICON_VS_FOLDER_OPENED, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBrown), buttonSize))
|
||||
if (ImGui::ToolBarButton(ICON_VS_FOLDER_OPENED, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBrown)))
|
||||
EventManager::post<RequestOpenWindow>("Open File");
|
||||
|
||||
|
||||
@@ -58,17 +56,17 @@ namespace hex::plugin::builtin {
|
||||
|
||||
// Save file
|
||||
ImGui::Disabled([&provider] {
|
||||
if (ImGui::ToolBarButton(ICON_VS_SAVE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize))
|
||||
if (ImGui::ToolBarButton(ICON_VS_SAVE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
provider->save();
|
||||
}, provider == nullptr || !provider->isWritable() || !provider->isSavable());
|
||||
}, !ImHexApi::Provider::isValid() || !provider->isWritable() || !provider->isSavable());
|
||||
|
||||
// Save file as
|
||||
ImGui::Disabled([&provider] {
|
||||
if (ImGui::ToolBarButton(ICON_VS_SAVE_AS, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize))
|
||||
if (ImGui::ToolBarButton(ICON_VS_SAVE_AS, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
hex::openFileBrowser("hex.view.hexeditor.save_as"_lang, DialogMode::Save, { }, [&provider](auto path) {
|
||||
provider->saveAs(path);
|
||||
});
|
||||
}, provider == nullptr || !provider->isSavable());
|
||||
}, !ImHexApi::Provider::isValid() || !provider->isSavable());
|
||||
|
||||
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
@@ -76,14 +74,39 @@ namespace hex::plugin::builtin {
|
||||
|
||||
// Create bookmark
|
||||
ImGui::Disabled([] {
|
||||
if (ImGui::ToolBarButton(ICON_VS_BOOKMARK, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen), buttonSize)) {
|
||||
if (ImGui::ToolBarButton(ICON_VS_BOOKMARK, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) {
|
||||
Region region = { 0 };
|
||||
EventManager::post<QuerySelection>(region);
|
||||
|
||||
ImHexApi::Bookmarks::add(region.address, region.size, { }, { });
|
||||
}
|
||||
}, provider == nullptr || !provider->isReadable());
|
||||
}, !ImHexApi::Provider::isValid() || !provider->isReadable());
|
||||
|
||||
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::Spacing();
|
||||
|
||||
// Provider switcher
|
||||
ImGui::Disabled([] {
|
||||
auto &providers = ImHexApi::Provider::getProviders();
|
||||
|
||||
std::string preview;
|
||||
if (ImHexApi::Provider::isValid())
|
||||
preview = providers[SharedData::currentProvider]->getName();
|
||||
|
||||
ImGui::SetNextItemWidth(200 * SharedData::globalScale);
|
||||
if (ImGui::BeginCombo("", preview.c_str())) {
|
||||
|
||||
for (int i = 0; i < providers.size(); i++) {
|
||||
if (ImGui::Selectable(providers[i]->getName().c_str())) {
|
||||
SharedData::currentProvider = i;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
}, !ImHexApi::Provider::isValid());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.decimal", "Dezimal" },
|
||||
{ "hex.common.hexadecimal", "Hexadezimal" },
|
||||
{ "hex.common.octal", "Oktal" },
|
||||
{ "hex.common.info", "Information" },
|
||||
{ "hex.common.error", "Fehler" },
|
||||
{ "hex.common.fatal", "Fataler Fehler" },
|
||||
{ "hex.common.address", "Adresse" },
|
||||
@@ -79,10 +80,15 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.dont_show_again", "Nicht mehr anzeigen" },
|
||||
{ "hex.common.link", "Link" },
|
||||
{ "hex.common.file", "Datei" },
|
||||
{ "hex.common.open", "Öffnen" },
|
||||
{ "hex.common.browse", "Druchsuchen..." },
|
||||
|
||||
{ "hex.message.yara_rule_added", "Yara Regel hinzugefügt!" },
|
||||
{ "hex.message.magic_db_added", "Magic Datenbank hinzugefügt!" },
|
||||
|
||||
{ "hex.view.bookmarks.name", "Lesezeichen" },
|
||||
{ "hex.view.bookmarks.default_title", "Lesezeichen [0x{0:X} - 0x{1:X}]" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "Noch kein Lesezeichen erstellt. Füge eines hinzu mit Bearbeiten -> Lesezeichen hinzufügen" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "Noch kein Lesezeichen erstellt. Füge eines hinzu mit Bearbeiten -> Lesezeichen erstellen" },
|
||||
{ "hex.view.bookmarks.title.info", "Informationen" },
|
||||
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} bytes)" },
|
||||
{ "hex.view.bookmarks.button.jump", "Springen" },
|
||||
@@ -96,6 +102,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.data_inspector.name", "Dateninspektor" },
|
||||
{ "hex.view.data_inspector.table.name", "Name" },
|
||||
{ "hex.view.data_inspector.table.value", "Wert" },
|
||||
{ "hex.view.data_inspector.no_data", "Keine bytes angewählt"},
|
||||
|
||||
{ "hex.view.data_processor.name", "Datenprozessor" },
|
||||
{ "hex.view.data_processor.menu.remove_selection", "Auswahl entfernen" },
|
||||
@@ -178,6 +185,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.hexeditor.menu.file.save", "Speichern" },
|
||||
{ "hex.view.hexeditor.menu.file.save_as", "Speichern unter..." },
|
||||
{ "hex.view.hexeditor.menu.file.close", "Schliessen" },
|
||||
{ "hex.view.hexeditor.menu.file.quit", "ImHex Beenden" },
|
||||
{ "hex.view.hexeditor.menu.file.open_project", "Projekt öffnen..." },
|
||||
{ "hex.view.hexeditor.menu.file.save_project", "Projekt speichern..." },
|
||||
{ "hex.view.hexeditor.menu.file.load_encoding_file", "Custom encoding laden..." },
|
||||
@@ -261,7 +269,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.pattern.auto", "Auto evaluieren" },
|
||||
|
||||
{ "hex.view.pattern_data.name", "Pattern Daten" },
|
||||
{ "hex.view.pattern_data.name", "Name" },
|
||||
{ "hex.view.pattern_data.var_name", "Name" },
|
||||
{ "hex.view.pattern_data.color", "Farbe" },
|
||||
{ "hex.view.pattern_data.offset", "Offset" },
|
||||
{ "hex.view.pattern_data.size", "Grösse" },
|
||||
@@ -276,6 +284,8 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.strings.min_length", "Minimallänge" },
|
||||
{ "hex.view.strings.filter", "Filter" },
|
||||
{ "hex.view.strings.extract", "Extrahieren" },
|
||||
{ "hex.view.strings.regex_error", "Ungültiges Regex" },
|
||||
{ "hex.view.strings.results", "{0} Ergebnisse" },
|
||||
{ "hex.view.strings.searching", "Suchen..." },
|
||||
{ "hex.view.strings.offset", "Offset" },
|
||||
{ "hex.view.strings.size", "Grösse" },
|
||||
@@ -293,6 +303,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.yara.error", "Yara Kompilerfehler: " },
|
||||
{ "hex.view.yara.header.matches", "Funde" },
|
||||
{ "hex.view.yara.matches.identifier", "Kennung" },
|
||||
{ "hex.view.yara.matches.variable", "Variabel" },
|
||||
{ "hex.view.yara.whole_data", "Gesammte Daten Übereinstimmung!" },
|
||||
{ "hex.view.yara.no_rules", "Keine Yara Regeln gefunden. Platziere sie in ImHex's 'yara' Ordner" },
|
||||
|
||||
@@ -314,7 +325,9 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.store.tab.libraries", "Libraries" },
|
||||
{ "hex.view.store.tab.magics", "Magic Files" },
|
||||
{ "hex.view.store.tab.constants", "Konstanten" },
|
||||
{ "hex.view.store.tab.yara", "Yara Rules" },
|
||||
{ "hex.view.store.loading", "Store inhalt wird geladen..." },
|
||||
{ "hex.view.diff.name", "Diffing" },
|
||||
|
||||
/* Builtin plugin features */
|
||||
|
||||
@@ -575,13 +588,56 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.tools.wiki_explain.search", "Suchen" },
|
||||
{ "hex.builtin.tools.wiki_explain.results", "Resultate" },
|
||||
{ "hex.builtin.tools.wiki_explain.invalid_response", "Ungültige Antwort von Wikipedia!" },
|
||||
{ "hex.builtin.tools.file_tools", "File Tools" },
|
||||
{ "hex.builtin.tools.file_tools.shredder", "Schredder" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.warning", "Dieses Tool zerstört eine Datei UNWIEDERRUFLICH. Mit Vorsicht verwenden" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.input", "Datei zum schreddern" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.picker", "Öffne Datei zum schreddern" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.fast", "Schneller Modus" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.shredding", "Schreddert..." },
|
||||
{ "hex.builtin.tools.file_tools.shredder.shred", "Schreddern" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.error.open", "Öffnen der ausgewählten Datei fehlgeschlagen" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.success", "Datei erfolgreich geschreddert!" },
|
||||
{ "hex.builtin.tools.file_tools.splitter", "Splitter" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "5¼\" Floppy disk (1200KiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "3½\" Floppy disk (1400KiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip 100 Disk (100MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip 200 Disk (200MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM (650MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM (700MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32 (4GiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "Benutzerdefiniert" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.input", "Zu splittende Datei " },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.input", "Zu splittende Datei öffnen" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.output", "Ziel Pfad" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.output", "Ziel Pfad setzen" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.splitting", "Splittet..." },
|
||||
{ "hex.builtin.tools.file_tools.splitter.split", "Splitten" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.error.open", "Öffnen der ausgewählten Datei fehlgeschlagen" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.error.size", "Datei ist kleiner als Zielgrösse" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.error.create", "Erstellen der Teildatei {0} fehlgeschlagen" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.success", "Datei erfolgreich gesplittet!" },
|
||||
{ "hex.builtin.tools.file_tools.combiner", "Kombinierer" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.add", "Hinzufügen..." },
|
||||
{ "hex.builtin.tools.file_tools.combiner.add.picker", "Datei hinzufügen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.delete", "Entfernen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.clear", "Alle entfernen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.output", "Zieldatei " },
|
||||
{ "hex.builtin.tools.file_tools.combiner.output.picker", "Ziel Pfad setzen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.combining", "Kombiniert..." },
|
||||
{ "hex.builtin.tools.file_tools.combiner.combine", "Kombinieren" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Erstellen der Zieldatei fehlgeschlagen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.open_input", "Öffnen der Inputdatei {0} fehlgeschlagen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.success", "Dateien erfolgreich kombiniert!" },
|
||||
|
||||
{ "hex.builtin.setting.imhex", "ImHex" },
|
||||
{ "hex.builtin.setting.imhex.recent_files", "Kürzlich geöffnete Dateien" },
|
||||
{ "hex.builtin.setting.general", "Allgemein" },
|
||||
{ "hex.builtin.setting.general.show_tips", "Tipps beim start anzeigen" },
|
||||
{ "hex.builtin.setting.general.auto_load_patterns", "Unterstützte Pattern automatisch laden" },
|
||||
{ "hex.builtin.setting.interface", "Aussehen" },
|
||||
{ "hex.builtin.setting.interface.color", "Farbthema" },
|
||||
{ "hex.builtin.setting.interface.color.system", "System" },
|
||||
{ "hex.builtin.setting.interface.color.dark", "Dunkel" },
|
||||
{ "hex.builtin.setting.interface.color.light", "Hell" },
|
||||
{ "hex.builtin.setting.interface.color.classic", "Klassisch" },
|
||||
@@ -593,7 +649,16 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.setting.interface.scaling.x2_0", "x2.0" },
|
||||
{ "hex.builtin.setting.interface.language", "Sprache" },
|
||||
{ "hex.builtin.setting.interface.fps", "FPS Limite" },
|
||||
{ "hex.builtin.setting.interface.fps.unlocked", "Unbegrenzt" },
|
||||
{ "hex.builtin.setting.interface.highlight_alpha", "Markierungssichtbarkeit" },
|
||||
{ "hex.builtin.setting.hex_editor", "Hex Editor" },
|
||||
{ "hex.builtin.setting.hex_editor.column_count", "Anzahl Byte Spalten" },
|
||||
{ "hex.builtin.setting.hex_editor.hexii", "HexII anstatt Bytes anzeigen" },
|
||||
{ "hex.builtin.setting.hex_editor.ascii", "ASCII Spalte anzeigen" },
|
||||
{ "hex.builtin.setting.hex_editor.advanced_decoding", "Erweiterte Dekodierungsspalte anzeigen" },
|
||||
{ "hex.builtin.setting.hex_editor.grey_zeros", "Nullen ausgrauen" },
|
||||
{ "hex.builtin.setting.hex_editor.uppercase_hex", "Hex Zeichen als Grossbuchstaben" },
|
||||
{ "hex.builtin.setting.hex_editor.extra_info", "Extra informationen anzeigen" },
|
||||
|
||||
{ "hex.builtin.provider.file.path", "Dateipfad" },
|
||||
{ "hex.builtin.provider.file.size", "Größe" },
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.welcome.learn.latest.desc", "Read ImHex's current changelog" },
|
||||
{ "hex.welcome.learn.latest.link", "https://github.com/WerWolv/ImHex/releases/latest" },
|
||||
{ "hex.welcome.learn.pattern.title", "Pattern Language Documentation" },
|
||||
{ "hex.welcome.learn.pattern.desc", "Learn how to write ImHex pattern_language with our extensive documentation" },
|
||||
{ "hex.welcome.learn.pattern.desc", "Learn how to write ImHex patterns with our extensive documentation" },
|
||||
{ "hex.welcome.learn.pattern.link", "https://imhex.werwolv.net/docs/pattern_language/pattern_language.html" },
|
||||
{ "hex.welcome.learn.plugins.title", "Plugins API" },
|
||||
{ "hex.welcome.learn.plugins.desc", "Extend ImHex with additional features using plugins" },
|
||||
@@ -63,6 +63,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.decimal", "Decimal" },
|
||||
{ "hex.common.hexadecimal", "Hexadecimal" },
|
||||
{ "hex.common.octal", "Octal" },
|
||||
{ "hex.common.info", "Information" },
|
||||
{ "hex.common.error", "Error" },
|
||||
{ "hex.common.fatal", "Fatal Error" },
|
||||
{ "hex.common.address", "Address" },
|
||||
@@ -79,10 +80,15 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.dont_show_again", "Don't show again" },
|
||||
{ "hex.common.link", "Link" },
|
||||
{ "hex.common.file", "File" },
|
||||
{ "hex.common.open", "Open" },
|
||||
{ "hex.common.browse", "Browse..." },
|
||||
|
||||
{ "hex.message.yara_rule_added", "Yara rule added!" },
|
||||
{ "hex.message.magic_db_added", "Magic database added!" },
|
||||
|
||||
{ "hex.view.bookmarks.name", "Bookmarks" },
|
||||
{ "hex.view.bookmarks.default_title", "Bookmark [0x{0:X} - 0x{1:X}]" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "No bookmarks created yet. Add one with Edit -> Add Bookmark" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "No bookmarks created yet. Add one with Edit -> Create Bookmark" },
|
||||
{ "hex.view.bookmarks.title.info", "Information" },
|
||||
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} bytes)" },
|
||||
{ "hex.view.bookmarks.button.jump", "Jump to" },
|
||||
@@ -96,6 +102,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.data_inspector.name", "Data Inspector" },
|
||||
{ "hex.view.data_inspector.table.name", "Name" },
|
||||
{ "hex.view.data_inspector.table.value", "Value" },
|
||||
{ "hex.view.data_inspector.no_data", "No bytes selected"},
|
||||
|
||||
{ "hex.view.data_processor.name", "Data Processor" },
|
||||
{ "hex.view.data_processor.menu.remove_selection", "Remove Selected" },
|
||||
@@ -139,6 +146,9 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.hashes.settings", "Settings" },
|
||||
{ "hex.view.hashes.function", "Hash function" },
|
||||
{ "hex.view.hashes.iv", "Initial value" },
|
||||
{ "hex.view.hashes.xorout", "Final XOR value" },
|
||||
{ "hex.common.reflectIn", "Reflect input" },
|
||||
{ "hex.common.reflectOut", "Reflect output" },
|
||||
{ "hex.view.hashes.poly", "Polynomial" },
|
||||
{ "hex.view.hashes.result", "Result" },
|
||||
|
||||
@@ -178,6 +188,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.hexeditor.menu.file.save", "Save" },
|
||||
{ "hex.view.hexeditor.menu.file.save_as", "Save As..." },
|
||||
{ "hex.view.hexeditor.menu.file.close", "Close" },
|
||||
{ "hex.view.hexeditor.menu.file.quit", "Quit ImHex" },
|
||||
{ "hex.view.hexeditor.menu.file.open_project", "Open Project..." },
|
||||
{ "hex.view.hexeditor.menu.file.save_project", "Save Project..." },
|
||||
{ "hex.view.hexeditor.menu.file.load_encoding_file", "Load custom encoding..." },
|
||||
@@ -261,7 +272,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.pattern.auto", "Auto evaluate" },
|
||||
|
||||
{ "hex.view.pattern_data.name", "Pattern Data" },
|
||||
{ "hex.view.pattern_data.name", "Name" },
|
||||
{ "hex.view.pattern_data.var_name", "Name" },
|
||||
{ "hex.view.pattern_data.color", "Color" },
|
||||
{ "hex.view.pattern_data.offset", "Offset" },
|
||||
{ "hex.view.pattern_data.size", "Size" },
|
||||
@@ -276,6 +287,8 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.strings.min_length", "Minimum length" },
|
||||
{ "hex.view.strings.filter", "Filter" },
|
||||
{ "hex.view.strings.extract", "Extract" },
|
||||
{ "hex.view.strings.regex_error", "Invalid regex" },
|
||||
{ "hex.view.strings.results", "Found {0} occurrences" },
|
||||
{ "hex.view.strings.searching", "Searching..." },
|
||||
{ "hex.view.strings.offset", "Offset" },
|
||||
{ "hex.view.strings.size", "Size" },
|
||||
@@ -293,6 +306,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.yara.error", "Yara Compiler error: " },
|
||||
{ "hex.view.yara.header.matches", "Matches" },
|
||||
{ "hex.view.yara.matches.identifier", "Identifier" },
|
||||
{ "hex.view.yara.matches.variable", "Variable" },
|
||||
{ "hex.view.yara.whole_data", "Whole file matches!" },
|
||||
{ "hex.view.yara.no_rules", "No YARA rules found. Put them in ImHex's 'yara' folder" },
|
||||
|
||||
@@ -314,7 +328,9 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.store.tab.libraries", "Libraries" },
|
||||
{ "hex.view.store.tab.magics", "Magic Files" },
|
||||
{ "hex.view.store.tab.constants", "Constants" },
|
||||
{ "hex.view.store.tab.yara", "Yara Rules" },
|
||||
{ "hex.view.store.loading", "Loading store content..." },
|
||||
{ "hex.view.diff.name", "Diffing" },
|
||||
|
||||
|
||||
/* Builtin plugin features */
|
||||
@@ -576,13 +592,56 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.tools.wiki_explain.search", "Search" },
|
||||
{ "hex.builtin.tools.wiki_explain.results", "Results" },
|
||||
{ "hex.builtin.tools.wiki_explain.invalid_response", "Invalid response from Wikipedia!" },
|
||||
{ "hex.builtin.tools.file_tools", "File Tools" },
|
||||
{ "hex.builtin.tools.file_tools.shredder", "Shredder" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.warning", "This tool IRRECOVERABLY destroys a file. Use with caution" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.input", "File to shred " },
|
||||
{ "hex.builtin.tools.file_tools.shredder.picker", "Open File to Shred" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.fast", "Fast Mode" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.shredding", "Shredding..." },
|
||||
{ "hex.builtin.tools.file_tools.shredder.shred", "Shred" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.error.open", "Failed to open selected file!" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.success", "Shredded successfully!" },
|
||||
{ "hex.builtin.tools.file_tools.splitter", "Splitter" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "5¼\" Floppy disk (1200KiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "3½\" Floppy disk (1400KiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip 100 Disk (100MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip 200 Disk (200MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM (650MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM (700MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32 (4GiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "Custom" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.input", "File to split " },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.input", "Open File to split" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.output", "Output path " },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.output", "Set base path" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.splitting", "Splitting..." },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.split", "Split" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.error.open", "Failed to open selected file!" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.error.size", "File is smaller than part size" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.error.create", "Failed to create part file {0}" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.success", "File split successfully!" },
|
||||
{ "hex.builtin.tools.file_tools.combiner", "Combiner" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.add", "Add..." },
|
||||
{ "hex.builtin.tools.file_tools.combiner.add.picker", "Add file" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.delete", "Delete" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.clear", "Clear" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.output", "Output file " },
|
||||
{ "hex.builtin.tools.file_tools.combiner.output.picker", "Set output base path" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.combining", "Combining..." },
|
||||
{ "hex.builtin.tools.file_tools.combiner.combine", "Combine" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Failed to create output file" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.open_input", "Failed to open input file {0}" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.success", "Files combined successfully!" },
|
||||
|
||||
{ "hex.builtin.setting.imhex", "ImHex" },
|
||||
{ "hex.builtin.setting.imhex.recent_files", "Recent Files" },
|
||||
{ "hex.builtin.setting.general", "General" },
|
||||
{ "hex.builtin.setting.general.show_tips", "Show tips on startup" },
|
||||
{ "hex.builtin.setting.general.auto_load_patterns", "Auto-load supported pattern" },
|
||||
{ "hex.builtin.setting.interface", "Interface" },
|
||||
{ "hex.builtin.setting.interface.color", "Color theme" },
|
||||
{ "hex.builtin.setting.interface.color.system", "System" },
|
||||
{ "hex.builtin.setting.interface.color.dark", "Dark" },
|
||||
{ "hex.builtin.setting.interface.color.light", "Light" },
|
||||
{ "hex.builtin.setting.interface.color.classic", "Classic" },
|
||||
@@ -594,7 +653,16 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.setting.interface.scaling.x2_0", "x2.0" },
|
||||
{ "hex.builtin.setting.interface.language", "Language" },
|
||||
{ "hex.builtin.setting.interface.fps", "FPS Limit" },
|
||||
{ "hex.builtin.setting.interface.fps.unlocked", "Unlocked" },
|
||||
{ "hex.builtin.setting.interface.highlight_alpha", "Highlighting opacity" },
|
||||
{ "hex.builtin.setting.hex_editor", "Hex Editor" },
|
||||
{ "hex.builtin.setting.hex_editor.column_count", "Byte column count" },
|
||||
{ "hex.builtin.setting.hex_editor.hexii", "Display HexII instead of Bytes" },
|
||||
{ "hex.builtin.setting.hex_editor.ascii", "Display ASCII column" },
|
||||
{ "hex.builtin.setting.hex_editor.advanced_decoding", "Display advanced decoding column" },
|
||||
{ "hex.builtin.setting.hex_editor.grey_zeros", "Grey out zeros" },
|
||||
{ "hex.builtin.setting.hex_editor.uppercase_hex", "Upper case Hex characters" },
|
||||
{ "hex.builtin.setting.hex_editor.extra_info", "Display extra information" },
|
||||
|
||||
{ "hex.builtin.provider.file.path", "File path" },
|
||||
{ "hex.builtin.provider.file.size", "Size" },
|
||||
@@ -604,4 +672,4 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.decimal", "Decimale" },
|
||||
{ "hex.common.hexadecimal", "Esadecimale" },
|
||||
{ "hex.common.octal", "Ottale" },
|
||||
//{ "hex.common.info", "Information" },
|
||||
{ "hex.common.error", "Errore" },
|
||||
{ "hex.common.fatal", "Errore Fatale" },
|
||||
{ "hex.common.address", "Indirizzo" },
|
||||
@@ -78,10 +79,15 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.dont_show_again", "Non mostrare di nuovo" },
|
||||
{ "hex.common.link", "Link" },
|
||||
{ "hex.common.file", "File" },
|
||||
//{ "hex.common.open", "Open" },
|
||||
//{ "hex.common.browse", "Browse..." },
|
||||
|
||||
//{ "hex.message.yara_rule_added", "Yara rule added!" },
|
||||
//{ "hex.message.magic_db_added", "Magic database added!" },
|
||||
|
||||
{ "hex.view.bookmarks.name", "Segnalibri" },
|
||||
{ "hex.view.bookmarks.default_title", "Segnalibro [0x{0:X} - 0x{1:X}]" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "Non è stato creato alcun segnalibro. Aggiungine uno andando su Modifica -> Aggiungi Segnalibro" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "Non è stato creato alcun segnalibro. Aggiungine uno andando su Modifica -> Crea Segnalibro" },
|
||||
{ "hex.view.bookmarks.title.info", "Informazioni" },
|
||||
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} bytes)" },
|
||||
{ "hex.view.bookmarks.button.jump", "Vai a" },
|
||||
@@ -95,6 +101,8 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.data_inspector.name", "Ispezione Dati" },
|
||||
{ "hex.view.data_inspector.table.name", "Nome" },
|
||||
{ "hex.view.data_inspector.table.value", "Valore" },
|
||||
//{ "hex.view.data_inspector.no_data", "No bytes selected"},
|
||||
|
||||
|
||||
{ "hex.view.data_processor.name", "Processa Dati" },
|
||||
{ "hex.view.data_processor.menu.remove_selection", "Rimuovi i selezionati" },
|
||||
@@ -177,6 +185,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.hexeditor.menu.file.save", "Salva" },
|
||||
{ "hex.view.hexeditor.menu.file.save_as", "Salva come..." },
|
||||
{ "hex.view.hexeditor.menu.file.close", "Chiudi" },
|
||||
{ "hex.view.hexeditor.menu.file.quit", "Uscita ImHex" },
|
||||
{ "hex.view.hexeditor.menu.file.open_project", "Apri un Progetto..." },
|
||||
{ "hex.view.hexeditor.menu.file.save_project", "Salva Progetto..." },
|
||||
{ "hex.view.hexeditor.menu.file.load_encoding_file", "Carica una codifica personalizzata..." },
|
||||
@@ -260,7 +269,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.pattern.auto", "Auto valutazione" },
|
||||
|
||||
{ "hex.view.pattern_data.name", "Dati dei Pattern" },
|
||||
{ "hex.view.pattern_data.name", "Nome" },
|
||||
{ "hex.view.pattern_data.var_name", "Nome" },
|
||||
{ "hex.view.pattern_data.color", "Colore" },
|
||||
{ "hex.view.pattern_data.offset", "Offset" },
|
||||
{ "hex.view.pattern_data.size", "Dimensione" },
|
||||
@@ -292,6 +301,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.yara.error", "Errore compilazione Yara: " },
|
||||
{ "hex.view.yara.header.matches", "Abbinamenti" },
|
||||
{ "hex.view.yara.matches.identifier", "Identificatore" },
|
||||
//{ "hex.view.yara.matches.variable", "Variable" },
|
||||
{ "hex.view.yara.whole_data", "Tutti i file combaciano!" },
|
||||
{ "hex.view.yara.no_rules", "Nessuna regola di YARA. Aggiungile in nella cartella 'yara' di 'ImHex'" },
|
||||
|
||||
@@ -301,19 +311,20 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.constants.row.desc", "Descrizione" },
|
||||
{ "hex.view.constants.row.value", "Valore" },
|
||||
{ "hex.view.store.name", "Content Store" },
|
||||
{ "hex.view.store.desc", "Scarica nuovi contenuti dal database online di ImHex" },
|
||||
{ "hex.view.store.reload", "Ricarica" },
|
||||
{ "hex.view.store.row.name", "Nome" },
|
||||
{ "hex.view.store.row.description", "Descrizione" },
|
||||
{ "hex.view.store.download", "Download" },
|
||||
{ "hex.view.store.update", "Aggiorna" },
|
||||
{ "hex.view.store.remove", "Rimuovi" },
|
||||
{ "hex.view.store.tab.patterns", "Modelli" },
|
||||
{ "hex.view.store.tab.libraries", "Librerie" },
|
||||
{ "hex.view.store.tab.magics", "File Magici" },
|
||||
{ "hex.view.store.tab.constants", "Costanti" },
|
||||
{ "hex.view.store.loading", "Caricamento del content store..." },
|
||||
|
||||
{ "hex.view.store.desc", "Scarica nuovi contenuti dal database online di ImHex" },
|
||||
{ "hex.view.store.reload", "Ricarica" },
|
||||
{ "hex.view.store.row.name", "Nome" },
|
||||
{ "hex.view.store.row.description", "Descrizione" },
|
||||
{ "hex.view.store.download", "Download" },
|
||||
{ "hex.view.store.update", "Aggiorna" },
|
||||
{ "hex.view.store.remove", "Rimuovi" },
|
||||
{ "hex.view.store.tab.patterns", "Modelli" },
|
||||
{ "hex.view.store.tab.libraries", "Librerie" },
|
||||
{ "hex.view.store.tab.magics", "File Magici" },
|
||||
{ "hex.view.store.tab.constants", "Costanti" },
|
||||
{ "hex.view.store.tab.yara", "Regole di Yara" },
|
||||
{ "hex.view.store.loading", "Caricamento del content store..." },
|
||||
//{ "hex.view.diff.name", "Diffing" },
|
||||
|
||||
/* Builtin plugin features */
|
||||
|
||||
@@ -574,13 +585,56 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.tools.wiki_explain.search", "Cerca" },
|
||||
{ "hex.builtin.tools.wiki_explain.results", "Risultati" },
|
||||
{ "hex.builtin.tools.wiki_explain.invalid_response", "Risposta non valida da Wikipedia!" },
|
||||
//{ "hex.builtin.tools.file_tools", "File Tools" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder", "Shredder" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.warning", "This tool IRRECOVERABLY destroys a file. Use with caution" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.input", "File to shred " },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.picker", "Open File to Shred" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.fast", "Fast Mode" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.shredding", "Shredding..." },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.shred", "Shred" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.error.open", "Failed to open selected file!" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.success", "Shredded successfully!" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter", "Splitter" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "5¼\" Floppy disk (1200KiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "3½\" Floppy disk (1400KiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip 100 Disk (100MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip 200 Disk (200MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM (650MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM (700MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32 (4GiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "Custom" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.input", "File to split " },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.input", "Open File to split" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.output", "Output path " },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.output", "Set base path" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.splitting", "Splitting..." },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.split", "Split" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.error.open", "Failed to open selected file!" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.error.size", "File is smaller than part size" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.error.create", "Failed to create part file {0}" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.success", "File split successfully!" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner", "Combiner" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.add", "Add..." },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.add.picker", "Add file" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.delete", "Delete" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.clear", "Clear" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.output", "Output file " },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.output.picker", "Set output base path" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.combining", "Combining..." },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.combine", "Combine" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Failed to create output file" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.open_input", "Failed to open input file {0}" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.success", "Files combined successfully!" },
|
||||
|
||||
{ "hex.builtin.setting.imhex", "ImHex" },
|
||||
{ "hex.builtin.setting.imhex.recent_files", "File recenti" },
|
||||
{ "hex.builtin.setting.general", "Generali" },
|
||||
{ "hex.builtin.setting.general.show_tips", "Mostra consigli all'avvio" },
|
||||
//{ "hex.builtin.setting.general.auto_load_patterns", "Auto-load supported pattern" },
|
||||
{ "hex.builtin.setting.interface", "Interfaccia" },
|
||||
{ "hex.builtin.setting.interface.color", "Colore del Tema" },
|
||||
{ "hex.builtin.setting.interface.color.system", "Sistema" },
|
||||
{ "hex.builtin.setting.interface.color.dark", "Scuro" },
|
||||
{ "hex.builtin.setting.interface.color.light", "Chiaro" },
|
||||
{ "hex.builtin.setting.interface.color.classic", "Classico" },
|
||||
@@ -591,8 +645,17 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.setting.interface.scaling.x1_0", "x1.0" },
|
||||
{ "hex.builtin.setting.interface.scaling.x1_5", "x1.5" },
|
||||
{ "hex.builtin.setting.interface.scaling.x2_0", "x2.0" },
|
||||
{ "hex.builtin.setting.interface.fps", "Limite FPS" },
|
||||
{ "hex.builtin.setting.interface.highlight_alpha", "Evidenziazione dell'opacità" },
|
||||
{ "hex.builtin.setting.interface.fps", "Limite FPS" },
|
||||
//{ "hex.builtin.setting.interface.fps.unlocked", "Unlocked" },
|
||||
{ "hex.builtin.setting.interface.highlight_alpha", "Evidenziazione dell'opacità" },
|
||||
//{ "hex.builtin.setting.hex_editor", "Hex Editor" },
|
||||
//{ "hex.builtin.setting.hex_editor.column_count", "Byte column count" },
|
||||
//{ "hex.builtin.setting.hex_editor.hexii", "Display HexII instead of Bytes" },
|
||||
//{ "hex.builtin.setting.hex_editor.ascii", "Display ASCII column" },
|
||||
//{ "hex.builtin.setting.hex_editor.advanced_decoding", "Display advanced decoding column" },
|
||||
//{ "hex.builtin.setting.hex_editor.grey_zeros", "Grey out zeros" },
|
||||
//{ "hex.builtin.setting.hex_editor.uppercase_hex", "Upper case Hex characters" },
|
||||
//{ "hex.builtin.setting.hex_editor.extra_info", "Display extra information" },
|
||||
|
||||
{ "hex.builtin.provider.file.path", "Percorso del File" },
|
||||
{ "hex.builtin.provider.file.size", "Dimensione" },
|
||||
|
||||
670
plugins/builtin/source/lang/zh_CN.cpp
Normal file
670
plugins/builtin/source/lang/zh_CN.cpp
Normal file
@@ -0,0 +1,670 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/helpers/lang.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void registerLanguageZhCN() {
|
||||
ContentRegistry::Language::registerLanguage("Chinese (Simplified)", "zh-CN");
|
||||
|
||||
ContentRegistry::Language::addLocalizations("zh-CN", {
|
||||
/* ImHex default functionality */
|
||||
{ "hex.menu.file", "文件" },
|
||||
{ "hex.menu.edit", "编辑" },
|
||||
{ "hex.menu.view", "视图" },
|
||||
{ "hex.menu.view.fps", "显示FPS" },
|
||||
{ "hex.menu.view.demo", "显示ImGui演示" },
|
||||
{ "hex.menu.help", "帮助" },
|
||||
{ "hex.menu.feedback", "反馈" },
|
||||
{ "hex.menu.debug_build", "调试构建"},
|
||||
|
||||
{ "hex.welcome.header.main", "欢迎来到ImHex" },
|
||||
{ "hex.welcome.header.start", "开始" },
|
||||
{ "hex.welcome.start.create_file", "创建新文件" },
|
||||
{ "hex.welcome.start.open_file", "打开文件" },
|
||||
{ "hex.welcome.start.open_project", "打开工程" },
|
||||
{ "hex.welcome.start.recent", "最近文件" },
|
||||
{ "hex.welcome.header.help", "帮助" },
|
||||
{ "hex.welcome.help.repo", "GitHub仓库" },
|
||||
{ "hex.welcome.help.repo.link", "https://github.com/WerWolv/ImHex" },
|
||||
{ "hex.welcome.help.gethelp", "获得帮助" },
|
||||
{ "hex.welcome.help.gethelp.link", "https://github.com/WerWolv/ImHex/discussions/categories/get-help" },
|
||||
{ "hex.welcome.header.plugins", "已加载插件" },
|
||||
{ "hex.welcome.plugins.plugin", "插件" },
|
||||
{ "hex.welcome.plugins.author", "作者" },
|
||||
{ "hex.welcome.plugins.desc", "描述" },
|
||||
{ "hex.welcome.header.customize", "自定义" },
|
||||
{ "hex.welcome.customize.settings.title", "设置" },
|
||||
{ "hex.welcome.customize.settings.desc", "更改ImHex的设置" },
|
||||
{ "hex.welcome.header.update", "更新" },
|
||||
{ "hex.welcome.update.title", "新的更新可用!" },
|
||||
{ "hex.welcome.update.desc", "ImHex {0} 已发布!在这里下载。" },
|
||||
{ "hex.welcome.update.link", "https://github.com/WerWolv/ImHex/releases/latest" },
|
||||
{ "hex.welcome.header.learn", "学习" },
|
||||
{ "hex.welcome.learn.latest.title", "最新版本" },
|
||||
{ "hex.welcome.learn.latest.desc", "阅读ImHex最新版本的更改日志" },
|
||||
{ "hex.welcome.learn.latest.link", "https://github.com/WerWolv/ImHex/releases/latest" },
|
||||
{ "hex.welcome.learn.pattern.title", "模式文档" },
|
||||
{ "hex.welcome.learn.pattern.desc", "如何基于我们完善的文档编写ImHex模式" },
|
||||
{ "hex.welcome.learn.pattern.link", "https://imhex.werwolv.net/docs/pattern_language/pattern_language.html" },
|
||||
{ "hex.welcome.learn.plugins.title", "插件API" },
|
||||
{ "hex.welcome.learn.plugins.desc", "通过插件扩展ImHex获得更多功能" },
|
||||
{ "hex.welcome.learn.plugins.link", "https://github.com/WerWolv/ImHex/wiki/Plugins-Development-Guide" },
|
||||
{ "hex.welcome.header.various", "杂项" },
|
||||
{ "hex.welcome.tip_of_the_day", "小提示" },
|
||||
|
||||
{ "hex.safety_backup.title", "恢复丢失数据" },
|
||||
{ "hex.safety_backup.desc", "不!ImHex上次崩溃了\n你想恢复你之前的工作吗?"},
|
||||
{ "hex.safety_backup.restore", "恢复" },
|
||||
{ "hex.safety_backup.delete", "删除" },
|
||||
|
||||
|
||||
{ "hex.common.little_endian", "小端序" },
|
||||
{ "hex.common.big_endian", "大端序" },
|
||||
{ "hex.common.decimal", "十进制" },
|
||||
{ "hex.common.hexadecimal", "十六进制" },
|
||||
{ "hex.common.octal", "八进制" },
|
||||
{ "hex.common.info", "信息" },
|
||||
{ "hex.common.error", "错误" },
|
||||
{ "hex.common.fatal", "致命错误" },
|
||||
{ "hex.common.address", "地址" },
|
||||
{ "hex.common.size", "大小" },
|
||||
{ "hex.common.region", "区域" },
|
||||
{ "hex.common.match_selection", "匹配选择" },
|
||||
{ "hex.common.yes", "是" },
|
||||
{ "hex.common.no", "否" },
|
||||
{ "hex.common.okay", "好的" },
|
||||
{ "hex.common.load", "加载" },
|
||||
{ "hex.common.cancel", "取消" },
|
||||
{ "hex.common.set", "设置" },
|
||||
{ "hex.common.close", "关闭文件" },
|
||||
{ "hex.common.dont_show_again", "不要再次显示" },
|
||||
{ "hex.common.link", "链接" },
|
||||
{ "hex.common.file", "文件" },
|
||||
{ "hex.common.open", "打开" },
|
||||
{ "hex.common.browse", "浏览..." },
|
||||
|
||||
{ "hex.message.yara_rule_added", "Yara规则已添加!" },
|
||||
{ "hex.message.magic_db_added", "魔术数据库已添加!" },
|
||||
|
||||
{ "hex.view.bookmarks.name", "书签" },
|
||||
{ "hex.view.bookmarks.default_title", "书签 [0x{0:X} - 0x{1:X}]" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "空空如也。通过 编辑->添加书签" },
|
||||
{ "hex.view.bookmarks.title.info", "信息" },
|
||||
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} 字节)" },
|
||||
{ "hex.view.bookmarks.button.jump", "转到" },
|
||||
{ "hex.view.bookmarks.button.remove", "移除" },
|
||||
{ "hex.view.bookmarks.header.name", "名称" },
|
||||
{ "hex.view.bookmarks.header.color", "颜色" },
|
||||
{ "hex.view.bookmarks.header.comment", "注释" },
|
||||
|
||||
{ "hex.view.command_palette.name", "命令栏" },
|
||||
|
||||
{ "hex.view.data_inspector.name", "数据分析器" },
|
||||
{ "hex.view.data_inspector.table.name", "名称" },
|
||||
{ "hex.view.data_inspector.table.value", "值" },
|
||||
{ "hex.view.data_inspector.no_data", "没有选中字节"},
|
||||
|
||||
{ "hex.view.data_processor.name", "数据处理器" },
|
||||
{ "hex.view.data_processor.menu.remove_selection", "移除已选" },
|
||||
{ "hex.view.data_processor.menu.remove_node", "移除节点" },
|
||||
{ "hex.view.data_processor.menu.remove_link", "移除链接" },
|
||||
|
||||
{ "hex.view.disassembler.name", "反汇编" },
|
||||
{ "hex.view.disassembler.position", "位置" },
|
||||
{ "hex.view.disassembler.base", "基地址" },
|
||||
{ "hex.view.disassembler.region", "代码范围" },
|
||||
{ "hex.view.disassembler.settings.header", "设置" },
|
||||
{ "hex.view.disassembler.arch", "架构" },
|
||||
{ "hex.view.disassembler.arm.arm", "ARM" },
|
||||
{ "hex.view.disassembler.arm.thumb", "Thumb" },
|
||||
{ "hex.view.disassembler.arm.default", "默认" },
|
||||
{ "hex.view.disassembler.arm.cortex_m", "Cortex-M" },
|
||||
{ "hex.view.disassembler.arm.armv8", "ARMv8" },
|
||||
|
||||
{ "hex.view.disassembler.mips.mips32", "MIPS32" },
|
||||
{ "hex.view.disassembler.mips.mips64", "MIPS64" },
|
||||
{ "hex.view.disassembler.mips.mips32R6", "MIPS32R6" },
|
||||
{ "hex.view.disassembler.mips.micro", "Micro MIPS" },
|
||||
|
||||
{ "hex.view.disassembler.x86.16bit", "16位" },
|
||||
{ "hex.view.disassembler.x86.32bit", "32位" },
|
||||
{ "hex.view.disassembler.x86.64bit", "64位" },
|
||||
|
||||
{ "hex.view.disassembler.ppc.32bit", "32位" },
|
||||
{ "hex.view.disassembler.ppc.64bit", "64位" },
|
||||
|
||||
{ "hex.view.disassembler.sparc.v9", "Sparc V9" },
|
||||
|
||||
{ "hex.view.disassembler.disassemble", "反汇编" },
|
||||
{ "hex.view.disassembler.disassembling", "反汇编中..." },
|
||||
{ "hex.view.disassembler.disassembly.title", "反汇编" },
|
||||
{ "hex.view.disassembler.disassembly.address", "地址" },
|
||||
{ "hex.view.disassembler.disassembly.offset", "偏移" },
|
||||
{ "hex.view.disassembler.disassembly.bytes", "字节" },
|
||||
|
||||
{ "hex.view.hashes.name", "哈希" },
|
||||
{ "hex.view.hashes.settings", "设置" },
|
||||
{ "hex.view.hashes.function", "哈希函数" },
|
||||
{ "hex.view.hashes.iv", "初始值" },
|
||||
{ "hex.view.hashes.poly", "多项式" },
|
||||
{ "hex.view.hashes.result", "结果" },
|
||||
|
||||
{ "hex.view.help.name", "帮助" },
|
||||
{ "hex.view.help.about.name", "关于" },
|
||||
{ "hex.view.help.about.translator", "由xtexChooser翻译" },
|
||||
{ "hex.view.help.about.source", "源代码位于GitHub:" },
|
||||
{ "hex.view.help.about.donations", "赞助" },
|
||||
{ "hex.view.help.about.thanks", "如果你喜欢我的工作,请赞助以帮助此项目继续前进。非常感谢 <3" },
|
||||
{ "hex.view.help.about.libs", "使用的库" },
|
||||
{ "hex.view.help.about.paths", "ImHex目录" },
|
||||
{ "hex.view.help.documentation", "ImHex文档" },
|
||||
{ "hex.view.help.pattern_cheat_sheet", "模式语言帮助"},
|
||||
{ "hex.view.help.calc_cheat_sheet", "计算器帮助" },
|
||||
|
||||
{ "hex.view.hexeditor.name", "Hex编辑器" },
|
||||
{ "hex.view.hexeditor.create_file", "新建" },
|
||||
{ "hex.view.hexeditor.open_file", "打开" },
|
||||
{ "hex.view.hexeditor.open_project", "打开项目" },
|
||||
{ "hex.view.hexeditor.save_project", "保存项目" },
|
||||
{ "hex.view.hexeditor.save_data", "保存数据" },
|
||||
{ "hex.view.hexeditor.open_base64", "打开Base64文件" },
|
||||
{ "hex.view.hexeditor.load_enconding_file", "加载自定义编码定义文件" },
|
||||
{ "hex.view.hexeditor.page", "页 {0} / {1}" },
|
||||
{ "hex.view.hexeditor.save_as", "另存为" },
|
||||
{ "hex.view.hexeditor.exit_application.title", "退出?" },
|
||||
{ "hex.view.hexeditor.exit_application.desc", "工程还有为保存的更改。\n确定要退出吗?" },
|
||||
{ "hex.view.hexeditor.script.title", "通过加载器脚本加载文件" },
|
||||
{ "hex.view.hexeditor.script.desc", "通过Python加载器脚本加载文件。" },
|
||||
{ "hex.view.hexeditor.script.script", "脚本" },
|
||||
{ "hex.view.hexeditor.script.script.title", "加载器脚本:打开脚本" },
|
||||
{ "hex.view.hexeditor.script.file", "文件" },
|
||||
{ "hex.view.hexeditor.script.file.title", "加载器脚本:打开文件" },
|
||||
|
||||
{ "hex.view.hexeditor.menu.file.open_file", "打开文件..." },
|
||||
{ "hex.view.hexeditor.menu.file.open_recent", "打开最近"},
|
||||
{ "hex.view.hexeditor.menu.file.save", "保存" },
|
||||
{ "hex.view.hexeditor.menu.file.save_as", "另存为..." },
|
||||
{ "hex.view.hexeditor.menu.file.close", "关闭" },
|
||||
{ "hex.view.hexeditor.menu.file.quit", "退出ImHex" },
|
||||
{ "hex.view.hexeditor.menu.file.open_project", "打开项目..." },
|
||||
{ "hex.view.hexeditor.menu.file.save_project", "保存项目..." },
|
||||
{ "hex.view.hexeditor.menu.file.load_encoding_file", "加载自定义编码..." },
|
||||
{ "hex.view.hexeditor.menu.file.import", "导入..." },
|
||||
{ "hex.view.hexeditor.menu.file.import.base64", "Base64文件" },
|
||||
{ "hex.view.hexeditor.base64.import_error", "文件不是有效的Base64格式!" },
|
||||
{ "hex.view.hexeditor.file_open_error", "打开文件失败!" },
|
||||
{ "hex.view.hexeditor.menu.file.import.ips", "IPS补丁" },
|
||||
{ "hex.view.hexeditor.menu.file.import.ips32", "IPS32补丁" },
|
||||
{ "hex.view.hexeditor.menu.file.import.script", "带有加载器脚本的文件" },
|
||||
|
||||
{ "hex.view.hexeditor.menu.file.export", "导出..." },
|
||||
{ "hex.view.hexeditor.menu.file.export.title", "导出文件" },
|
||||
{ "hex.view.hexeditor.menu.file.export.ips", "IPS补丁" },
|
||||
{ "hex.view.hexeditor.menu.file.export.ips32", "IPS32补丁" },
|
||||
{ "hex.view.hexeditor.menu.file.search", "搜索" },
|
||||
{ "hex.view.hexeditor.search.string", "字符串" },
|
||||
{ "hex.view.hexeditor.search.hex", "Hex" },
|
||||
{ "hex.view.hexeditor.search.find", "查找" },
|
||||
{ "hex.view.hexeditor.search.find_next", "查找下一个" },
|
||||
{ "hex.view.hexeditor.search.find_prev", "查找上一个" },
|
||||
{ "hex.view.hexeditor.menu.file.goto", "转到" },
|
||||
{ "hex.view.hexeditor.goto.offset.absolute", "绝对" },
|
||||
{ "hex.view.hexeditor.goto.offset.current", "当前" },
|
||||
{ "hex.view.hexeditor.goto.offset.begin", "起始" },
|
||||
{ "hex.view.hexeditor.goto.offset.end", "末尾" },
|
||||
{ "hex.view.hexeditor.error.read_only", "无法获得写权限,文件以只读方式打开。" },
|
||||
{ "hex.view.hexeditor.error.open", "打开文件失败!" },
|
||||
{ "hex.view.hexeditor.error.create", "创建新文件失败!" },
|
||||
{ "hex.view.hexeditor.menu.edit.undo", "撤销" },
|
||||
{ "hex.view.hexeditor.menu.edit.redo", "重做" },
|
||||
{ "hex.view.hexeditor.menu.edit.copy", "复制" },
|
||||
{ "hex.view.hexeditor.menu.edit.copy_as", "复制为..." },
|
||||
{ "hex.view.hexeditor.copy.hex", "字符串" },
|
||||
{ "hex.view.hexeditor.copy.c", "C数组" },
|
||||
{ "hex.view.hexeditor.copy.cpp", "C++数组" },
|
||||
{ "hex.view.hexeditor.copy.csharp", "C#数组" },
|
||||
{ "hex.view.hexeditor.copy.rust", "Rust数组" },
|
||||
{ "hex.view.hexeditor.copy.python", "Python数组" },
|
||||
{ "hex.view.hexeditor.copy.java", "Java数组" },
|
||||
{ "hex.view.hexeditor.copy.js", "JavaScript数组" },
|
||||
{ "hex.view.hexeditor.copy.ascii", "ASCII Art" },
|
||||
{ "hex.view.hexeditor.copy.html", "HTML" },
|
||||
{ "hex.view.hexeditor.menu.edit.paste", "粘贴" },
|
||||
{ "hex.view.hexeditor.menu.edit.select_all", "全选" },
|
||||
{ "hex.view.hexeditor.menu.edit.bookmark", "添加书签" },
|
||||
{ "hex.view.hexeditor.menu.edit.set_base", "设置基地址" },
|
||||
{ "hex.view.hexeditor.menu.edit.resize", "修改大小" },
|
||||
|
||||
{ "hex.view.information.name", "数据信息" },
|
||||
{ "hex.view.information.control", "控制" },
|
||||
{ "hex.view.information.analyze", "分析" },
|
||||
{ "hex.view.information.analyzing", "分析中..." },
|
||||
{ "hex.view.information.region", "已分析区域" },
|
||||
{ "hex.view.information.magic", "魔术信息" },
|
||||
{ "hex.view.information.description", "描述:" },
|
||||
{ "hex.view.information.mime", "MIME类型:" },
|
||||
{ "hex.view.information.info_analysis", "信息分析" },
|
||||
{ "hex.view.information.distribution", "字节分布" },
|
||||
{ "hex.view.information.entropy", "熵" },
|
||||
{ "hex.view.information.block_size", "块大小" },
|
||||
{ "hex.view.information.block_size.desc", "{0} 块 × {1} 字节" },
|
||||
{ "hex.view.information.file_entropy", "文件熵" },
|
||||
{ "hex.view.information.highest_entropy", "最高熵" },
|
||||
{ "hex.view.information.encrypted", "此数据似乎经过了加密或压缩!" },
|
||||
|
||||
{ "hex.view.patches.name", "补丁" },
|
||||
{ "hex.view.patches.offset", "偏移" },
|
||||
{ "hex.view.patches.orig", "原始值" },
|
||||
{ "hex.view.patches.patch", "修改值"},
|
||||
{ "hex.view.patches.remove", "移除补丁" },
|
||||
|
||||
{ "hex.view.pattern.name", "模式编辑器" },
|
||||
{ "hex.view.pattern.accept_pattern", "接受模式" },
|
||||
{ "hex.view.pattern.accept_pattern.desc", "一个或多个模式与所找到的数据类型兼容" },
|
||||
{ "hex.view.pattern.accept_pattern.pattern_language", "模式" },
|
||||
{ "hex.view.pattern.accept_pattern.question", "是否应用找到的模式?" },
|
||||
{ "hex.view.pattern.menu.file.load_pattern", "加载模式文件..." },
|
||||
{ "hex.view.pattern.open_pattern", "打开模式" },
|
||||
{ "hex.view.pattern.evaluating", "计算中..." },
|
||||
{ "hex.view.pattern.auto", "自动计算" },
|
||||
|
||||
{ "hex.view.pattern_data.name", "模式数据" },
|
||||
{ "hex.view.pattern_data.var_name", "名称" },
|
||||
{ "hex.view.pattern_data.color", "颜色" },
|
||||
{ "hex.view.pattern_data.offset", "偏移" },
|
||||
{ "hex.view.pattern_data.size", "大小" },
|
||||
{ "hex.view.pattern_data.type", "类型" },
|
||||
{ "hex.view.pattern_data.value", "值" },
|
||||
|
||||
{ "hex.view.settings.name", "设置" },
|
||||
|
||||
{ "hex.view.strings.name", "字符串" },
|
||||
{ "hex.view.strings.copy", "复制字符串" },
|
||||
{ "hex.view.strings.demangle", "还原" },
|
||||
{ "hex.view.strings.min_length", "最小长度" },
|
||||
{ "hex.view.strings.filter", "过滤" },
|
||||
{ "hex.view.strings.extract", "提取" },
|
||||
{ "hex.view.strings.searching", "搜索中..." },
|
||||
{ "hex.view.strings.offset", "偏移" },
|
||||
{ "hex.view.strings.size", "大小" },
|
||||
{ "hex.view.strings.string", "字符串" },
|
||||
{ "hex.view.strings.demangle.title", "还原名" },
|
||||
{ "hex.view.strings.demangle.copy", "复制" },
|
||||
|
||||
{ "hex.view.tools.name", "工具" },
|
||||
|
||||
{ "hex.view.yara.name", "Yara规则" },
|
||||
{ "hex.view.yara.header.rules", "规则" },
|
||||
{ "hex.view.yara.reload", "重新加载" },
|
||||
{ "hex.view.yara.match", "匹配规则" },
|
||||
{ "hex.view.yara.matching", "匹配中..." },
|
||||
{ "hex.view.yara.error", "Yara编译器错误: " },
|
||||
{ "hex.view.yara.header.matches", "匹配" },
|
||||
{ "hex.view.yara.matches.identifier", "标识符" },
|
||||
//{ "hex.view.yara.matches.variable", "Variable" },
|
||||
{ "hex.view.yara.whole_data", "全文件匹配!" },
|
||||
{ "hex.view.yara.no_rules", "没有找到YARA规则。请将规则放到ImHex的'yara'目录下。" },
|
||||
|
||||
{ "hex.view.constants.name", "常量" },
|
||||
{ "hex.view.constants.row.category", "分类" },
|
||||
{ "hex.view.constants.row.name", "名称" },
|
||||
{ "hex.view.constants.row.desc", "描述" },
|
||||
{ "hex.view.constants.row.value", "值" },
|
||||
|
||||
{ "hex.view.store.name", "内容仓库" },
|
||||
{ "hex.view.store.desc", "从ImHex在线数据库下载新内容" },
|
||||
{ "hex.view.store.reload", "刷新" },
|
||||
{ "hex.view.store.row.name", "名称" },
|
||||
{ "hex.view.store.row.description", "描述" },
|
||||
{ "hex.view.store.download", "下载" },
|
||||
{ "hex.view.store.update", "更新" },
|
||||
{ "hex.view.store.remove", "移除" },
|
||||
{ "hex.view.store.tab.patterns", "模式" },
|
||||
{ "hex.view.store.tab.libraries", "库" },
|
||||
{ "hex.view.store.tab.magics", "魔术数据库" },
|
||||
{ "hex.view.store.tab.constants", "常量" },
|
||||
{ "hex.view.store.tab.yara", "Yara规则" },
|
||||
{ "hex.view.store.loading", "正在加载仓库内容..." },
|
||||
{ "hex.view.diff.name", "差异" },
|
||||
|
||||
/* Builtin plugin features */
|
||||
|
||||
{ "hex.builtin.command.calc.desc", "计算器" },
|
||||
{ "hex.builtin.command.cmd.desc", "指令" },
|
||||
{ "hex.builtin.command.cmd.result", "运行指令 '{0}'" },
|
||||
{ "hex.builtin.command.web.desc", "网站解析" },
|
||||
{ "hex.builtin.command.web.result", "导航到 '{0}'" },
|
||||
|
||||
// Use half width symbols for inspector names because displayable space
|
||||
{ "hex.builtin.inspector.binary", "二进制(8位)" },
|
||||
{ "hex.builtin.inspector.u8", "uint8_t" },
|
||||
{ "hex.builtin.inspector.s8", "int8_t" },
|
||||
{ "hex.builtin.inspector.u16", "uint16_t" },
|
||||
{ "hex.builtin.inspector.s16", "int16_t" },
|
||||
{ "hex.builtin.inspector.u32", "uint32_t" },
|
||||
{ "hex.builtin.inspector.s32", "int32_t" },
|
||||
{ "hex.builtin.inspector.u64", "uint64_t" },
|
||||
{ "hex.builtin.inspector.s64", "int64_t" },
|
||||
{ "hex.builtin.inspector.float16", "半浮点(16位)" },
|
||||
{ "hex.builtin.inspector.float", "float(32位单精度浮点)" },
|
||||
{ "hex.builtin.inspector.double", "double(64位双精度浮点)" },
|
||||
{ "hex.builtin.inspector.ascii", "ASCII字符" },
|
||||
{ "hex.builtin.inspector.wide", "宽字符" },
|
||||
{ "hex.builtin.inspector.utf8", "UTF-8代码点" },
|
||||
{ "hex.builtin.inspector.string", "字符串" },
|
||||
{ "hex.builtin.inspector.time32", "__time32_t" },
|
||||
{ "hex.builtin.inspector.time64", "__time64_t" },
|
||||
{ "hex.builtin.inspector.time", "time_t" },
|
||||
{ "hex.builtin.inspector.guid", "GUID" },
|
||||
{ "hex.builtin.inspector.rgba8", "RGBA8颜色" },
|
||||
|
||||
{ "hex.builtin.nodes.constants", "常量" },
|
||||
{ "hex.builtin.nodes.constants.int", "整数" },
|
||||
{ "hex.builtin.nodes.constants.int.header", "整数" },
|
||||
{ "hex.builtin.nodes.constants.int.output", "" },
|
||||
{ "hex.builtin.nodes.constants.float", "浮点数" },
|
||||
{ "hex.builtin.nodes.constants.float.header", "浮点数" },
|
||||
{ "hex.builtin.nodes.constants.float.output", "" },
|
||||
{ "hex.builtin.nodes.constants.nullptr", "空指针" },
|
||||
{ "hex.builtin.nodes.constants.nullptr.header", "空指针" },
|
||||
{ "hex.builtin.nodes.constants.nullptr.output", "" },
|
||||
{ "hex.builtin.nodes.constants.buffer", "缓冲区" },
|
||||
{ "hex.builtin.nodes.constants.buffer.header", "缓冲区" },
|
||||
{ "hex.builtin.nodes.constants.buffer.size", "大小" },
|
||||
{ "hex.builtin.nodes.constants.buffer.output", "" },
|
||||
{ "hex.builtin.nodes.constants.string", "字符串" },
|
||||
{ "hex.builtin.nodes.constants.string.header", "字符串" },
|
||||
{ "hex.builtin.nodes.constants.string.output", "" },
|
||||
{ "hex.builtin.nodes.constants.rgba8", "RGBA8颜色" },
|
||||
{ "hex.builtin.nodes.constants.rgba8.header", "RGBA8颜色" },
|
||||
{ "hex.builtin.nodes.constants.rgba8.output.r", "红" },
|
||||
{ "hex.builtin.nodes.constants.rgba8.output.g", "绿" },
|
||||
{ "hex.builtin.nodes.constants.rgba8.output.b", "蓝" },
|
||||
{ "hex.builtin.nodes.constants.rgba8.output.a", "透明" },
|
||||
{ "hex.builtin.nodes.constants.comment", "注释" },
|
||||
{ "hex.builtin.nodes.constants.comment.header", "注释" },
|
||||
|
||||
{ "hex.builtin.nodes.display", "显示" },
|
||||
{ "hex.builtin.nodes.display.int", "整数" },
|
||||
{ "hex.builtin.nodes.display.int.header", "整数显示" },
|
||||
{ "hex.builtin.nodes.display.int.input", "值" },
|
||||
{ "hex.builtin.nodes.display.float", "浮点数" },
|
||||
{ "hex.builtin.nodes.display.float.header", "浮点数显示" },
|
||||
{ "hex.builtin.nodes.display.float.input", "值" },
|
||||
|
||||
{ "hex.builtin.nodes.data_access", "数据访问" },
|
||||
{ "hex.builtin.nodes.data_access.read", "读取" },
|
||||
{ "hex.builtin.nodes.data_access.read.header", "读取" },
|
||||
{ "hex.builtin.nodes.data_access.read.address", "地址" },
|
||||
{ "hex.builtin.nodes.data_access.read.size", "大小" },
|
||||
{ "hex.builtin.nodes.data_access.read.data", "数据" },
|
||||
{ "hex.builtin.nodes.data_access.write", "写入" },
|
||||
{ "hex.builtin.nodes.data_access.write.header", "写入" },
|
||||
{ "hex.builtin.nodes.data_access.write.address", "地址" },
|
||||
{ "hex.builtin.nodes.data_access.write.data", "数据" },
|
||||
{ "hex.builtin.nodes.data_access.size", "数据大小"},
|
||||
{ "hex.builtin.nodes.data_access.size.header", "数据大小"},
|
||||
{ "hex.builtin.nodes.data_access.size.size", "大小"},
|
||||
|
||||
{ "hex.builtin.nodes.casting", "数据转换" },
|
||||
{ "hex.builtin.nodes.casting.int_to_buffer", "整数到缓冲区" },
|
||||
{ "hex.builtin.nodes.casting.int_to_buffer.header", "整数到缓冲区" },
|
||||
{ "hex.builtin.nodes.casting.int_to_buffer.input", "输入" },
|
||||
{ "hex.builtin.nodes.casting.int_to_buffer.output", "输出" },
|
||||
{ "hex.builtin.nodes.casting.buffer_to_int", "缓冲区到整数" },
|
||||
{ "hex.builtin.nodes.casting.buffer_to_int.header", "缓冲区到整数" },
|
||||
{ "hex.builtin.nodes.casting.buffer_to_int.input", "输入" },
|
||||
{ "hex.builtin.nodes.casting.buffer_to_int.output", "输出" },
|
||||
|
||||
{ "hex.builtin.nodes.arithmetic", "运算" },
|
||||
{ "hex.builtin.nodes.arithmetic.add", "加法" },
|
||||
{ "hex.builtin.nodes.arithmetic.add.header", "加法" },
|
||||
{ "hex.builtin.nodes.arithmetic.add.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.arithmetic.add.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.arithmetic.add.output", "输出" },
|
||||
{ "hex.builtin.nodes.arithmetic.sub", "减法" },
|
||||
{ "hex.builtin.nodes.arithmetic.sub.header", "减法" },
|
||||
{ "hex.builtin.nodes.arithmetic.sub.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.arithmetic.sub.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.arithmetic.sub.output", "输出" },
|
||||
{ "hex.builtin.nodes.arithmetic.mul", "乘法" },
|
||||
{ "hex.builtin.nodes.arithmetic.mul.header", "乘法" },
|
||||
{ "hex.builtin.nodes.arithmetic.mul.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.arithmetic.mul.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.arithmetic.mul.output", "输出" },
|
||||
{ "hex.builtin.nodes.arithmetic.div", "除法" },
|
||||
{ "hex.builtin.nodes.arithmetic.div.header", "除法" },
|
||||
{ "hex.builtin.nodes.arithmetic.div.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.arithmetic.div.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.arithmetic.div.output", "输出" },
|
||||
{ "hex.builtin.nodes.arithmetic.mod", "模数" },
|
||||
{ "hex.builtin.nodes.arithmetic.mod.header", "模数" },
|
||||
{ "hex.builtin.nodes.arithmetic.mod.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.arithmetic.mod.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.arithmetic.mod.output", "输出" },
|
||||
|
||||
{ "hex.builtin.nodes.buffer", "缓冲区" },
|
||||
{ "hex.builtin.nodes.buffer.combine", "组合" },
|
||||
{ "hex.builtin.nodes.buffer.combine.header", "缓冲区组合" },
|
||||
{ "hex.builtin.nodes.buffer.combine.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.buffer.combine.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.buffer.combine.output", "输出" },
|
||||
{ "hex.builtin.nodes.buffer.slice", "切片" },
|
||||
{ "hex.builtin.nodes.buffer.slice.header", "缓冲区切片" },
|
||||
{ "hex.builtin.nodes.buffer.slice.input.buffer", "输入" },
|
||||
{ "hex.builtin.nodes.buffer.slice.input.from", "从" },
|
||||
{ "hex.builtin.nodes.buffer.slice.input.to", "到" },
|
||||
{ "hex.builtin.nodes.buffer.slice.output", "输出" },
|
||||
{ "hex.builtin.nodes.buffer.repeat", "重复" },
|
||||
{ "hex.builtin.nodes.buffer.repeat.header", "缓冲区重复" },
|
||||
{ "hex.builtin.nodes.buffer.repeat.input.buffer", "输入" },
|
||||
{ "hex.builtin.nodes.buffer.repeat.input.count", "次数" },
|
||||
{ "hex.builtin.nodes.buffer.repeat.output", "输出" },
|
||||
|
||||
{ "hex.builtin.nodes.control_flow", "控制流" },
|
||||
{ "hex.builtin.nodes.control_flow.if", "如果" },
|
||||
{ "hex.builtin.nodes.control_flow.if.header", "如果" },
|
||||
{ "hex.builtin.nodes.control_flow.if.condition", "条件" },
|
||||
{ "hex.builtin.nodes.control_flow.if.true", "True" },
|
||||
{ "hex.builtin.nodes.control_flow.if.false", "False" },
|
||||
{ "hex.builtin.nodes.control_flow.if.output", "输出" },
|
||||
{ "hex.builtin.nodes.control_flow.equals", "等于" },
|
||||
{ "hex.builtin.nodes.control_flow.equals.header", "等于" },
|
||||
{ "hex.builtin.nodes.control_flow.equals.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.control_flow.equals.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.control_flow.equals.output", "输出" },
|
||||
{ "hex.builtin.nodes.control_flow.not", "取反" },
|
||||
{ "hex.builtin.nodes.control_flow.not.header", "取反" },
|
||||
{ "hex.builtin.nodes.control_flow.not.input", "输入" },
|
||||
{ "hex.builtin.nodes.control_flow.not.output", "输出" },
|
||||
{ "hex.builtin.nodes.control_flow.gt", "大于" },
|
||||
{ "hex.builtin.nodes.control_flow.gt.header", "大于" },
|
||||
{ "hex.builtin.nodes.control_flow.gt.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.control_flow.gt.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.control_flow.gt.output", "输出" },
|
||||
{ "hex.builtin.nodes.control_flow.lt", "小于" },
|
||||
{ "hex.builtin.nodes.control_flow.lt.header", "小于" },
|
||||
{ "hex.builtin.nodes.control_flow.lt.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.control_flow.lt.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.control_flow.lt.output", "输出" },
|
||||
{ "hex.builtin.nodes.control_flow.and", "与" },
|
||||
{ "hex.builtin.nodes.control_flow.and.header", "逻辑与" },
|
||||
{ "hex.builtin.nodes.control_flow.and.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.control_flow.and.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.control_flow.and.output", "输出" },
|
||||
{ "hex.builtin.nodes.control_flow.or", "或" },
|
||||
{ "hex.builtin.nodes.control_flow.or.header", "逻辑或" },
|
||||
{ "hex.builtin.nodes.control_flow.or.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.control_flow.or.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.control_flow.or.output", "输出" },
|
||||
|
||||
{ "hex.builtin.nodes.bitwise", "按位操作" },
|
||||
{ "hex.builtin.nodes.bitwise.and", "与" },
|
||||
{ "hex.builtin.nodes.bitwise.and.header", "位与" },
|
||||
{ "hex.builtin.nodes.bitwise.and.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.bitwise.and.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.bitwise.and.output", "输出" },
|
||||
{ "hex.builtin.nodes.bitwise.or", "或" },
|
||||
{ "hex.builtin.nodes.bitwise.or.header", "位或" },
|
||||
{ "hex.builtin.nodes.bitwise.or.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.bitwise.or.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.bitwise.or.output", "输出" },
|
||||
{ "hex.builtin.nodes.bitwise.xor", "异或" },
|
||||
{ "hex.builtin.nodes.bitwise.xor.header", "按位异或" },
|
||||
{ "hex.builtin.nodes.bitwise.xor.input.a", "输入A" },
|
||||
{ "hex.builtin.nodes.bitwise.xor.input.b", "输入B" },
|
||||
{ "hex.builtin.nodes.bitwise.xor.output", "输出" },
|
||||
{ "hex.builtin.nodes.bitwise.not", "取反" },
|
||||
{ "hex.builtin.nodes.bitwise.not.header", "按位取反" },
|
||||
{ "hex.builtin.nodes.bitwise.not.input", "输入" },
|
||||
{ "hex.builtin.nodes.bitwise.not.output", "输出" },
|
||||
|
||||
{ "hex.builtin.nodes.decoding", "编码" },
|
||||
{ "hex.builtin.nodes.decoding.base64", "Base64" },
|
||||
{ "hex.builtin.nodes.decoding.base64.header", "Base64解码" },
|
||||
{ "hex.builtin.nodes.decoding.base64.input", "输入" },
|
||||
{ "hex.builtin.nodes.decoding.base64.output", "输出" },
|
||||
{ "hex.builtin.nodes.decoding.hex", "十六进制" },
|
||||
{ "hex.builtin.nodes.decoding.hex.header", "十六进制解码" },
|
||||
{ "hex.builtin.nodes.decoding.hex.input", "输入" },
|
||||
{ "hex.builtin.nodes.decoding.hex.output", "输出" },
|
||||
|
||||
{ "hex.builtin.nodes.crypto", "加密" },
|
||||
{ "hex.builtin.nodes.crypto.aes", "AES解密" },
|
||||
{ "hex.builtin.nodes.crypto.aes.header", "AES解密" },
|
||||
{ "hex.builtin.nodes.crypto.aes.key", "密钥" },
|
||||
{ "hex.builtin.nodes.crypto.aes.iv", "IV" },
|
||||
{ "hex.builtin.nodes.crypto.aes.nonce", "Nonce" },
|
||||
{ "hex.builtin.nodes.crypto.aes.input", "输入" },
|
||||
{ "hex.builtin.nodes.crypto.aes.output", "输出" },
|
||||
{ "hex.builtin.nodes.crypto.aes.mode", "模式" },
|
||||
{ "hex.builtin.nodes.crypto.aes.key_length", "密钥长度" },
|
||||
|
||||
|
||||
|
||||
{ "hex.builtin.tools.demangler", "Itanium/MSVC名还原" },
|
||||
{ "hex.builtin.tools.demangler.mangled", "修饰名" },
|
||||
{ "hex.builtin.tools.demangler.demangled", "还原名" },
|
||||
{ "hex.builtin.tools.ascii_table", "ASCII表" },
|
||||
{ "hex.builtin.tools.ascii_table.octal", "显示八进制" },
|
||||
{ "hex.builtin.tools.regex_replacer", "正则替换" },
|
||||
{ "hex.builtin.tools.regex_replacer.pattern", "正则表达式" },
|
||||
{ "hex.builtin.tools.regex_replacer.replace", "替换表达式" },
|
||||
{ "hex.builtin.tools.regex_replacer.input", "输入" },
|
||||
{ "hex.builtin.tools.regex_replacer.output", "输出" },
|
||||
{ "hex.builtin.tools.color", "颜色选择器" },
|
||||
{ "hex.builtin.tools.calc", "计算器" },
|
||||
{ "hex.builtin.tools.input", "输入" },
|
||||
{ "hex.builtin.tools.format.standard", "标准" },
|
||||
{ "hex.builtin.tools.format.scientific", "科学" },
|
||||
{ "hex.builtin.tools.format.engineering", "工程师" },
|
||||
{ "hex.builtin.tools.format.programmer", "程序员" },
|
||||
{ "hex.builtin.tools.error", "最后错误: '{0}'" },
|
||||
{ "hex.builtin.tools.history", "历史" },
|
||||
{ "hex.builtin.tools.name", "名称" },
|
||||
{ "hex.builtin.tools.value", "值" },
|
||||
{ "hex.builtin.tools.base_converter", "基本进制转换" },
|
||||
{ "hex.builtin.tools.base_converter.dec", "DEC" },
|
||||
{ "hex.builtin.tools.base_converter.hex", "HEX" },
|
||||
{ "hex.builtin.tools.base_converter.oct", "OCT" },
|
||||
{ "hex.builtin.tools.base_converter.bin", "BIN" },
|
||||
{ "hex.builtin.tools.permissions", "UNIX权限计算器" },
|
||||
{ "hex.builtin.tools.permissions.perm_bits", "权限位" },
|
||||
{ "hex.builtin.tools.permissions.absolute", "绝对符号" },
|
||||
{ "hex.builtin.tools.permissions.setuid_error", "用户必须具有 setuid 位的执行权限才能应用!" },
|
||||
{ "hex.builtin.tools.permissions.setgid_error", "组必须具有 setgid 位的执行权限才能应用!" },
|
||||
{ "hex.builtin.tools.permissions.sticky_error", "必须有执行权限才能申请粘滞位!" },
|
||||
{ "hex.builtin.tools.file_uploader", "文件上传" },
|
||||
{ "hex.builtin.tools.file_uploader.control", "控制" },
|
||||
{ "hex.builtin.tools.file_uploader.upload", "上传" },
|
||||
{ "hex.builtin.tools.file_uploader.done", "完成!" },
|
||||
{ "hex.builtin.tools.file_uploader.recent", "最近上传" },
|
||||
{ "hex.builtin.tools.file_uploader.tooltip", "点击复制\n按住CTRL并点击以打开" },
|
||||
{ "hex.builtin.tools.file_uploader.invalid_response", "接收到来自Anonfiles的无效响应!" },
|
||||
{ "hex.builtin.tools.file_uploader.error", "上传文件失败!\n\n错误代码:{0}" },
|
||||
{ "hex.builtin.tools.wiki_explain", "维基百科术语定义" },
|
||||
{ "hex.builtin.tools.wiki_explain.control", "控制" },
|
||||
{ "hex.builtin.tools.wiki_explain.search", "搜索" },
|
||||
{ "hex.builtin.tools.wiki_explain.results", "结果" },
|
||||
{ "hex.builtin.tools.wiki_explain.invalid_response", "接收到来自Wikipedia的无效响应!" },
|
||||
{ "hex.builtin.tools.file_tools", "文件工具" },
|
||||
{ "hex.builtin.tools.file_tools.shredder", "销毁" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.warning", "此工具将不可恢复地破坏文件。请谨慎使用。" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.input", "目标文件 " },
|
||||
{ "hex.builtin.tools.file_tools.shredder.picker", "打开文件以销毁" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.fast", "快速模式" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.shredding", "销毁中..." },
|
||||
{ "hex.builtin.tools.file_tools.shredder.shred", "销毁" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.error.open", "打开选择的文件失败!" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.success", "文件成功销毁!" },
|
||||
{ "hex.builtin.tools.file_tools.splitter", "分割" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "5寸软盘(1200KiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "3寸软盘(1400KiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip极碟100(100MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip极碟200(200MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM(650MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM(700MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32(4GiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "自定义" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.input", "目标文件 " },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.input", "打开文件以分割" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.output", "输出路径 " },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.output", "选择输出路径" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.splitting", "分割中..." },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.split", "分割" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.error.open", "打开选择的文件失败!" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.error.size", "文件小于单分块大小" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.error.create", "创建分块文件 {0} 失败!" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.success", "文件分割成功!" },
|
||||
{ "hex.builtin.tools.file_tools.combiner", "合并" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.add", "添加..." },
|
||||
{ "hex.builtin.tools.file_tools.combiner.add.picker", "添加文件" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.delete", "删除" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.clear", "清空" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.output", "输出文件 " },
|
||||
{ "hex.builtin.tools.file_tools.combiner.output.picker", "选择输出路径" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.combining", "合并中..." },
|
||||
{ "hex.builtin.tools.file_tools.combiner.combine", "合并" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.error.open_output", "创建输出文件失败!" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.open_input", "打开输入文件 {0} 失败" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.success", "文件合并成功!" },
|
||||
|
||||
{ "hex.builtin.setting.imhex", "ImHex" },
|
||||
{ "hex.builtin.setting.imhex.recent_files", "最近文件" },
|
||||
{ "hex.builtin.setting.general", "通用" },
|
||||
{ "hex.builtin.setting.general.show_tips", "在启动时显示每日提示" },
|
||||
{ "hex.builtin.setting.general.auto_load_patterns", "自动加载支持的模式" },
|
||||
{ "hex.builtin.setting.interface", "界面" },
|
||||
{ "hex.builtin.setting.interface.color", "颜色主题" },
|
||||
{ "hex.builtin.setting.interface.color.system", "跟随系统" },
|
||||
{ "hex.builtin.setting.interface.color.dark", "暗" },
|
||||
{ "hex.builtin.setting.interface.color.light", "亮" },
|
||||
{ "hex.builtin.setting.interface.color.classic", "经典" },
|
||||
{ "hex.builtin.setting.interface.scaling", "缩放" },
|
||||
{ "hex.builtin.setting.interface.scaling.native", "本地默认" },
|
||||
{ "hex.builtin.setting.interface.scaling.x0_5", "x0.5" },
|
||||
{ "hex.builtin.setting.interface.scaling.x1_0", "x1.0" },
|
||||
{ "hex.builtin.setting.interface.scaling.x1_5", "x1.5" },
|
||||
{ "hex.builtin.setting.interface.scaling.x2_0", "x2.0" },
|
||||
{ "hex.builtin.setting.interface.language", "语言" },
|
||||
{ "hex.builtin.setting.interface.fps", "FPS限制" },
|
||||
{ "hex.builtin.setting.interface.fps.unlocked", "无限制" },
|
||||
{ "hex.builtin.setting.interface.highlight_alpha", "高亮不透明度" },
|
||||
{ "hex.builtin.setting.hex_editor", "Hex编辑器" },
|
||||
{ "hex.builtin.setting.hex_editor.column_count", "字节列数" },
|
||||
{ "hex.builtin.setting.hex_editor.hexii", "显示HexII替代字节" },
|
||||
{ "hex.builtin.setting.hex_editor.ascii", "显示ASCII栏" },
|
||||
{ "hex.builtin.setting.hex_editor.advanced_decoding", "显示高级解码栏" },
|
||||
{ "hex.builtin.setting.hex_editor.grey_zeros", "显示零字节为灰色" },
|
||||
{ "hex.builtin.setting.hex_editor.uppercase_hex", "大写Hex字符" },
|
||||
{ "hex.builtin.setting.hex_editor.extra_info", "显示额外信息" },
|
||||
|
||||
{ "hex.builtin.provider.file.path", "路径" },
|
||||
{ "hex.builtin.provider.file.size", "大小" },
|
||||
{ "hex.builtin.provider.file.creation", "创建时间" },
|
||||
{ "hex.builtin.provider.file.access", "最后访问时间" },
|
||||
{ "hex.builtin.provider.file.modification", "最后更改时间" },
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,6 +15,7 @@ namespace hex::plugin::builtin {
|
||||
void registerLanguageEnUS();
|
||||
void registerLanguageDeDE();
|
||||
void registerLanguageItIT();
|
||||
void registerLanguageZhCN();
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +36,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
registerLanguageEnUS();
|
||||
registerLanguageDeDE();
|
||||
registerLanguageItIT();
|
||||
registerLanguageZhCN();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# Change this to the name of your plugin #
|
||||
project(example)
|
||||
project(example_cpp)
|
||||
|
||||
# Add your source files here #
|
||||
add_library(${PROJECT_NAME} SHARED
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
IMHEX_PLUGIN_SETUP("Example", "WerWolv", "Example plugin used as template for plugin devs") {
|
||||
IMHEX_PLUGIN_SETUP("Example C++", "WerWolv", "Example C++ plugin used as template for plugin devs") {
|
||||
|
||||
ContentRegistry::Views::add<ViewExample>();
|
||||
|
||||
44
plugins/example_rust/CMakeLists.txt
Normal file
44
plugins/example_rust/CMakeLists.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# Change this to the name of your plugin #
|
||||
project(example_rust)
|
||||
|
||||
# ---- No need to change anything from here downwards unless you know what you're doing ---- #
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CARGO_CMD ${RUST_PATH}cargo build)
|
||||
set(TARGET_DIR "debug")
|
||||
else ()
|
||||
set(CARGO_CMD ${RUST_PATH}cargo build --release)
|
||||
set(TARGET_DIR "release")
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
set(PLUGIN_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_DIR}/${PROJECT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
else ()
|
||||
set(PLUGIN_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${PROJECT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
endif ()
|
||||
|
||||
get_target_property(LIBIMHEX_SOURCE_DIRECTORY libimhex SOURCE_DIR)
|
||||
|
||||
add_custom_target(${PROJECT_NAME} ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E env
|
||||
CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR}
|
||||
LIBIMHEX_SOURCE_DIRECTORY=${LIBIMHEX_SOURCE_DIRECTORY}
|
||||
LIBIMHEX_OUTPUT_DIRECTORY=$<TARGET_FILE_DIR:libimhex>
|
||||
CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
${CARGO_CMD}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PLUGIN_OUTPUT_PATH} "${CMAKE_CURRENT_BINARY_DIR}/../${PROJECT_NAME}.hexplug"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
VERBATIM
|
||||
USES_TERMINAL
|
||||
)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES LOCATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES RUST_PROJECT 1)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE Rust)
|
||||
|
||||
add_compile_definitions(IMHEX_PLUGIN_NAME=${PROJECT_NAME})
|
||||
|
||||
if (NOT TARGET libimhex)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libimhex ${CMAKE_CURRENT_BINARY_DIR}/plugins/libimhex)
|
||||
endif()
|
||||
295
plugins/example_rust/Cargo.lock
generated
Normal file
295
plugins/example_rust/Cargo.lock
generated
Normal file
@@ -0,0 +1,295 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chlorine"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd650552110e39b7c5058986cf177decd3365841836578ac50a286094eac0be6"
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "638fb099591b763a988ca69e5f0ee4b82bedb8bc762b3c6cfbfdd3a6dc6b54b4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"link-cplusplus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83363b96cfd226eb820e37a21088c30c55e47f9fc8299c2d08a6090d50414ccc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"lazy_static",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d4bde25840be4cf0eb1d7e3a74634105189d5609b855bcc8d601ffb037f5f4"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3869bf8972075de8f0446b433d40026f2dfdbd8a9edbc24e9d645ca2ebf2f93a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "example_rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"hex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
"imgui",
|
||||
"macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imgui"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"imgui-sys",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imgui-sys"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"chlorine",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1becd27d473556dc610b8afa1636ef90747b574a84553bc11e82371d5ef2d1"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e114536316b51a5aa7a0e59fc49661fd263c5507dd08bd28de052e57626ce69"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
15
plugins/example_rust/Cargo.toml
Normal file
15
plugins/example_rust/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "example_rust"
|
||||
version = "0.1.0"
|
||||
authors = ["WerWolv <hey@werwolv.net>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
path = "source/plugin_example.rs"
|
||||
|
||||
[dependencies]
|
||||
hex = { path = "../libimhex-rust" }
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
7
plugins/example_rust/source/plugin_example.rs
Normal file
7
plugins/example_rust/source/plugin_example.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
extern crate hex;
|
||||
|
||||
#[hex::plugin_setup("Example Rust", "WerWolv", "Example Rust plugin used as template for plugin devs")]
|
||||
fn init() {
|
||||
|
||||
}
|
||||
|
||||
288
plugins/libimhex-rust/Cargo.lock
generated
Normal file
288
plugins/libimhex-rust/Cargo.lock
generated
Normal file
@@ -0,0 +1,288 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chlorine"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd650552110e39b7c5058986cf177decd3365841836578ac50a286094eac0be6"
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "638fb099591b763a988ca69e5f0ee4b82bedb8bc762b3c6cfbfdd3a6dc6b54b4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"link-cplusplus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83363b96cfd226eb820e37a21088c30c55e47f9fc8299c2d08a6090d50414ccc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"lazy_static",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d4bde25840be4cf0eb1d7e3a74634105189d5609b855bcc8d601ffb037f5f4"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3869bf8972075de8f0446b433d40026f2dfdbd8a9edbc24e9d645ca2ebf2f93a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
"imgui",
|
||||
"macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imgui"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"imgui-sys",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imgui-sys"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"chlorine",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1becd27d473556dc610b8afa1636ef90747b574a84553bc11e82371d5ef2d1"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e114536316b51a5aa7a0e59fc49661fd263c5507dd08bd28de052e57626ce69"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
16
plugins/libimhex-rust/Cargo.toml
Normal file
16
plugins/libimhex-rust/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "hex"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
macros = { path = "proc_macros" }
|
||||
imgui = { path = "imgui-rs" }
|
||||
|
||||
cxx = "1.0.55"
|
||||
|
||||
[build-dependencies]
|
||||
cxx-build = "1.0.55"
|
||||
15
plugins/libimhex-rust/build.rs
Normal file
15
plugins/libimhex-rust/build.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
fn main() {
|
||||
println!("cargo:rustc-link-lib=dylib=imhex");
|
||||
println!("cargo:rustc-link-search=all={}", env!("LIBIMHEX_OUTPUT_DIRECTORY"));
|
||||
|
||||
println!("cargo:rerun-if-changed=src/lib.rs");
|
||||
println!("cargo:rerun-if-changed=src/imhex_api.rs");
|
||||
|
||||
cxx_build::bridge("src/imhex_api.rs")
|
||||
.include(format!("{}/include", env!("LIBIMHEX_SOURCE_DIRECTORY")))
|
||||
.flag_if_supported("-std=gnu++20")
|
||||
.flag_if_supported("-std=gnu++2a")
|
||||
.flag_if_supported("-fconcepts")
|
||||
.compiler(env!("CXX_COMPILER"))
|
||||
.compile("libimhex-bridge");
|
||||
}
|
||||
159
plugins/libimhex-rust/imgui-rs/Cargo.lock
generated
vendored
Normal file
159
plugins/libimhex-rust/imgui-rs/Cargo.lock
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chlorine"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd650552110e39b7c5058986cf177decd3365841836578ac50a286094eac0be6"
|
||||
|
||||
[[package]]
|
||||
name = "imgui"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"imgui-sys",
|
||||
"memoffset",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imgui-sys"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"chlorine",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
31
plugins/libimhex-rust/imgui-rs/Cargo.toml
vendored
Normal file
31
plugins/libimhex-rust/imgui-rs/Cargo.toml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
[package]
|
||||
name = "imgui"
|
||||
version = "0.8.0"
|
||||
edition = "2018"
|
||||
authors = ["The imgui-rs Developers"]
|
||||
description = "High-level Rust bindings to dear imgui"
|
||||
homepage = "https://github.com/imgui-rs/imgui-rs"
|
||||
repository = "https://github.com/imgui-rs/imgui-rs"
|
||||
license = "MIT/Apache-2.0"
|
||||
categories = ["gui", "api-bindings"]
|
||||
readme = "../README.markdown"
|
||||
|
||||
exclude = ["/resources"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1"
|
||||
imgui-sys = { path = "../imgui-sys" }
|
||||
parking_lot = "0.11"
|
||||
|
||||
[features]
|
||||
default = ["min-const-generics"]
|
||||
|
||||
wasm = ["imgui-sys/wasm"]
|
||||
freetype = ["imgui-sys/freetype"]
|
||||
min-const-generics = []
|
||||
# this api is in beta in the upstream imgui crate. See issue #524 for more info.
|
||||
# it should be stable and fine to use though.
|
||||
tables-api = []
|
||||
|
||||
[dev-dependencies]
|
||||
memoffset = "0.6"
|
||||
202
plugins/libimhex-rust/imgui-rs/LICENSE-APACHE
vendored
Normal file
202
plugins/libimhex-rust/imgui-rs/LICENSE-APACHE
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
19
plugins/libimhex-rust/imgui-rs/LICENSE-MIT
vendored
Normal file
19
plugins/libimhex-rust/imgui-rs/LICENSE-MIT
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2015-2020 The imgui-rs Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1
plugins/libimhex-rust/imgui-rs/README.markdown
vendored
Symbolic link
1
plugins/libimhex-rust/imgui-rs/README.markdown
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../README.markdown
|
||||
142
plugins/libimhex-rust/imgui-rs/src/clipboard.rs
vendored
Normal file
142
plugins/libimhex-rust/imgui-rs/src/clipboard.rs
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fmt;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use std::panic::catch_unwind;
|
||||
use std::process;
|
||||
use std::ptr;
|
||||
|
||||
// use crate::string::{ImStr, ImString};
|
||||
use crate::Ui;
|
||||
|
||||
/// Trait for clipboard backends
|
||||
pub trait ClipboardBackend: 'static {
|
||||
/// Returns the current clipboard contents as an owned imgui-rs string, or None if the
|
||||
/// clipboard is empty or inaccessible
|
||||
fn get(&mut self) -> Option<String>;
|
||||
/// Sets the clipboard contents to the given imgui-rs string slice.
|
||||
fn set(&mut self, value: &str);
|
||||
}
|
||||
|
||||
pub(crate) struct ClipboardContext {
|
||||
backend: Box<dyn ClipboardBackend>,
|
||||
// this is needed to keep ownership of the value when the raw C callback is called
|
||||
last_value: CString,
|
||||
}
|
||||
|
||||
impl ClipboardContext {
|
||||
/// Creates a new [ClipboardContext]. This function previously took a `Box`, but now
|
||||
/// is generic over the T it takes and boxes itself (which should be less strange).
|
||||
pub fn new<T: ClipboardBackend>(backend: T) -> ClipboardContext {
|
||||
ClipboardContext {
|
||||
backend: Box::new(backend) as Box<dyn ClipboardBackend>,
|
||||
last_value: CString::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dummy() -> ClipboardContext {
|
||||
Self {
|
||||
backend: Box::new(DummyClipboardContext),
|
||||
last_value: CString::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DummyClipboardContext;
|
||||
impl ClipboardBackend for DummyClipboardContext {
|
||||
fn get(&mut self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
fn set(&mut self, _: &str) {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ClipboardContext {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ClipboardContext")
|
||||
// beautiful code, no?
|
||||
.field("backend", &(&(*self.backend) as *const _))
|
||||
.field("last_value", &self.last_value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe extern "C" fn get_clipboard_text(user_data: *mut c_void) -> *const c_char {
|
||||
let result = catch_unwind(|| {
|
||||
let ctx = &mut *(user_data as *mut ClipboardContext);
|
||||
match ctx.backend.get() {
|
||||
Some(text) => {
|
||||
ctx.last_value = CString::new(text).unwrap();
|
||||
ctx.last_value.as_ptr()
|
||||
}
|
||||
None => ptr::null(),
|
||||
}
|
||||
});
|
||||
result.unwrap_or_else(|_| {
|
||||
eprintln!("Clipboard getter panicked");
|
||||
process::abort();
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) unsafe extern "C" fn set_clipboard_text(user_data: *mut c_void, text: *const c_char) {
|
||||
let result = catch_unwind(|| {
|
||||
let ctx = &mut *(user_data as *mut ClipboardContext);
|
||||
let text = CStr::from_ptr(text).to_owned();
|
||||
ctx.backend.set(text.to_str().unwrap());
|
||||
});
|
||||
result.unwrap_or_else(|_| {
|
||||
eprintln!("Clipboard setter panicked");
|
||||
process::abort();
|
||||
});
|
||||
}
|
||||
|
||||
/// # Clipboard
|
||||
#[allow(clippy::fn_address_comparisons)] // This is allowed because although function addresses wont be unique, we just care if its OURS
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Returns the current clipboard contents as text, or None if the clipboard is empty or cannot
|
||||
/// be accessed
|
||||
pub fn clipboard_text(&self) -> Option<String> {
|
||||
let io = self.io();
|
||||
io.get_clipboard_text_fn.and_then(|get_clipboard_text_fn| {
|
||||
// Bypass FFI if we end up calling our own function anyway
|
||||
if get_clipboard_text_fn == get_clipboard_text {
|
||||
let ctx = unsafe { &mut *(io.clipboard_user_data as *mut ClipboardContext) };
|
||||
ctx.backend.get()
|
||||
} else {
|
||||
unsafe {
|
||||
let text_ptr = get_clipboard_text_fn(io.clipboard_user_data);
|
||||
if text_ptr.is_null() || *text_ptr == b'\0' as c_char {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
CStr::from_ptr(text_ptr)
|
||||
.to_owned()
|
||||
.to_str()
|
||||
.ok()?
|
||||
.to_owned(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the clipboard contents.
|
||||
///
|
||||
/// Does nothing if the clipboard cannot be accessed.
|
||||
pub fn set_clipboard_text(&self, text: impl AsRef<str>) {
|
||||
let io = self.io();
|
||||
if let Some(set_clipboard_text_fn) = io.set_clipboard_text_fn {
|
||||
// Bypass FFI if we end up calling our own function anyway
|
||||
if set_clipboard_text_fn == set_clipboard_text {
|
||||
let ctx = unsafe { &mut *(io.clipboard_user_data as *mut ClipboardContext) };
|
||||
ctx.backend.set(text.as_ref());
|
||||
} else {
|
||||
unsafe {
|
||||
set_clipboard_text_fn(io.clipboard_user_data, self.scratch_txt(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
370
plugins/libimhex-rust/imgui-rs/src/color.rs
vendored
Normal file
370
plugins/libimhex-rust/imgui-rs/src/color.rs
vendored
Normal file
@@ -0,0 +1,370 @@
|
||||
/// Wraps u32 that represents a packed RGBA color. Mostly used by types in the
|
||||
/// low level custom drawing API, such as [`DrawListMut`](crate::DrawListMut).
|
||||
///
|
||||
/// The bits of a color are in "`0xAABBGGRR`" format (e.g. RGBA as little endian
|
||||
/// bytes). For clarity: we don't support an equivalent to the
|
||||
/// `IMGUI_USE_BGRA_PACKED_COLOR` define.
|
||||
///
|
||||
/// This used to be named `ImColor32`, but was renamed to avoid confusion with
|
||||
/// the type with that name in the C++ API (which uses 32 bits per channel).
|
||||
///
|
||||
/// While it doesn't provide methods to access the fields, they can be accessed
|
||||
/// via the `Deref`/`DerefMut` impls it provides targeting
|
||||
/// [`imgui::color::ImColor32Fields`](crate::color::ImColor32Fields), which has
|
||||
/// no other meaningful uses.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// let mut c = imgui::ImColor32::from_rgba(0x80, 0xc0, 0x40, 0xff);
|
||||
/// assert_eq!(c.to_bits(), 0xff_40_c0_80); // Note: 0xAA_BB_GG_RR
|
||||
/// // Field access
|
||||
/// assert_eq!(c.r, 0x80);
|
||||
/// assert_eq!(c.g, 0xc0);
|
||||
/// assert_eq!(c.b, 0x40);
|
||||
/// assert_eq!(c.a, 0xff);
|
||||
/// c.b = 0xbb;
|
||||
/// assert_eq!(c.to_bits(), 0xff_bb_c0_80);
|
||||
/// ```
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct ImColor32(u32); // TBH maybe the wrapped field should be `pub`.
|
||||
|
||||
impl ImColor32 {
|
||||
/// Convenience constant for solid black.
|
||||
pub const BLACK: Self = Self(0xff_00_00_00);
|
||||
|
||||
/// Convenience constant for solid white.
|
||||
pub const WHITE: Self = Self(0xff_ff_ff_ff);
|
||||
|
||||
/// Convenience constant for full transparency.
|
||||
pub const TRANSPARENT: Self = Self(0);
|
||||
|
||||
/// Construct a color from 4 single-byte `u8` channel values, which should
|
||||
/// be between 0 and 255.
|
||||
#[inline]
|
||||
pub const fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
Self(
|
||||
((a as u32) << Self::A_SHIFT)
|
||||
| ((r as u32) << Self::R_SHIFT)
|
||||
| ((g as u32) << Self::G_SHIFT)
|
||||
| ((b as u32) << Self::B_SHIFT),
|
||||
)
|
||||
}
|
||||
|
||||
/// Construct a fully opaque color from 3 single-byte `u8` channel values.
|
||||
/// Same as [`Self::from_rgba`] with a == 255
|
||||
#[inline]
|
||||
pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
|
||||
Self::from_rgba(r, g, b, 0xff)
|
||||
}
|
||||
|
||||
/// Construct a fully opaque color from 4 `f32` channel values in the range
|
||||
/// `0.0 ..= 1.0` (values outside this range are clamped to it, with NaN
|
||||
/// mapped to 0.0).
|
||||
///
|
||||
/// Note: No alpha premultiplication is done, so your input should be have
|
||||
/// premultiplied alpha if needed.
|
||||
#[inline]
|
||||
// not const fn because no float math in const eval yet 😩
|
||||
pub fn from_rgba_f32s(r: f32, g: f32, b: f32, a: f32) -> Self {
|
||||
Self::from_rgba(
|
||||
f32_to_u8_sat(r),
|
||||
f32_to_u8_sat(g),
|
||||
f32_to_u8_sat(b),
|
||||
f32_to_u8_sat(a),
|
||||
)
|
||||
}
|
||||
|
||||
/// Return the channels as an array of f32 in `[r, g, b, a]` order.
|
||||
#[inline]
|
||||
pub fn to_rgba_f32s(self) -> [f32; 4] {
|
||||
let &ImColor32Fields { r, g, b, a } = &*self;
|
||||
[
|
||||
u8_to_f32_sat(r),
|
||||
u8_to_f32_sat(g),
|
||||
u8_to_f32_sat(b),
|
||||
u8_to_f32_sat(a),
|
||||
]
|
||||
}
|
||||
|
||||
/// Return the channels as an array of u8 in `[r, g, b, a]` order.
|
||||
#[inline]
|
||||
pub fn to_rgba(self) -> [u8; 4] {
|
||||
let &ImColor32Fields { r, g, b, a } = &*self;
|
||||
[r, g, b, a]
|
||||
}
|
||||
|
||||
/// Equivalent to [`Self::from_rgba_f32s`], but with an alpha of 1.0 (e.g.
|
||||
/// opaque).
|
||||
#[inline]
|
||||
pub fn from_rgb_f32s(r: f32, g: f32, b: f32) -> Self {
|
||||
Self::from_rgba(f32_to_u8_sat(r), f32_to_u8_sat(g), f32_to_u8_sat(b), 0xff)
|
||||
}
|
||||
|
||||
/// Construct a color from the `u32` that makes up the bits in `0xAABBGGRR`
|
||||
/// format.
|
||||
///
|
||||
/// Specifically, this takes the RGBA values as a little-endian u32 with 8
|
||||
/// bits per channel.
|
||||
///
|
||||
/// Note that [`ImColor32::from_rgba`] may be a bit easier to use.
|
||||
#[inline]
|
||||
pub const fn from_bits(u: u32) -> Self {
|
||||
Self(u)
|
||||
}
|
||||
|
||||
/// Return the bits of the color as a u32. These are in "`0xAABBGGRR`" format, that
|
||||
/// is, little-endian RGBA with 8 bits per channel.
|
||||
#[inline]
|
||||
pub const fn to_bits(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
// These are public in C++ ImGui, should they be public here?
|
||||
/// The number of bits to shift the byte of the red channel. Always 0.
|
||||
const R_SHIFT: u32 = 0;
|
||||
/// The number of bits to shift the byte of the green channel. Always 8.
|
||||
const G_SHIFT: u32 = 8;
|
||||
/// The number of bits to shift the byte of the blue channel. Always 16.
|
||||
const B_SHIFT: u32 = 16;
|
||||
/// The number of bits to shift the byte of the alpha channel. Always 24.
|
||||
const A_SHIFT: u32 = 24;
|
||||
}
|
||||
|
||||
impl Default for ImColor32 {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::TRANSPARENT
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ImColor32 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ImColor32")
|
||||
.field("r", &self.r)
|
||||
.field("g", &self.g)
|
||||
.field("b", &self.b)
|
||||
.field("a", &self.a)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct that exists to allow field access to [`ImColor32`]. It essentially
|
||||
/// exists to be a `Deref`/`DerefMut` target and provide field access.
|
||||
///
|
||||
/// Note that while this is repr(C), be aware that on big-endian machines
|
||||
/// (`cfg(target_endian = "big")`) the order of the fields is reversed, as this
|
||||
/// is a view into a packed u32.
|
||||
///
|
||||
/// Generally should not be used, except as the target of the `Deref` impl of
|
||||
/// [`ImColor32`].
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, align(4))]
|
||||
// Should this be #[non_exhaustive] to discourage direct use?
|
||||
#[rustfmt::skip]
|
||||
pub struct ImColor32Fields {
|
||||
#[cfg(target_endian = "little")] pub r: u8,
|
||||
#[cfg(target_endian = "little")] pub g: u8,
|
||||
#[cfg(target_endian = "little")] pub b: u8,
|
||||
#[cfg(target_endian = "little")] pub a: u8,
|
||||
// TODO(someday): i guess we should have BE tests, but for now I verified
|
||||
// this locally.
|
||||
#[cfg(target_endian = "big")] pub a: u8,
|
||||
#[cfg(target_endian = "big")] pub b: u8,
|
||||
#[cfg(target_endian = "big")] pub g: u8,
|
||||
#[cfg(target_endian = "big")] pub r: u8,
|
||||
}
|
||||
|
||||
// We assume that big and little are the only endiannesses, and that exactly one
|
||||
// is set. That is, PDP endian is not in use, and the we aren't using a
|
||||
// completely broken custom target json or something.
|
||||
#[cfg(any(
|
||||
all(target_endian = "little", target_endian = "big"),
|
||||
all(not(target_endian = "little"), not(target_endian = "big")),
|
||||
))]
|
||||
compile_error!("`cfg(target_endian = \"little\")` must be `cfg(not(target_endian = \"big\")`");
|
||||
|
||||
// static assert sizes match
|
||||
const _: [(); core::mem::size_of::<ImColor32>()] = [(); core::mem::size_of::<ImColor32Fields>()];
|
||||
const _: [(); core::mem::align_of::<ImColor32>()] = [(); core::mem::align_of::<ImColor32Fields>()];
|
||||
|
||||
impl core::ops::Deref for ImColor32 {
|
||||
type Target = ImColor32Fields;
|
||||
#[inline]
|
||||
fn deref(&self) -> &ImColor32Fields {
|
||||
// Safety: we statically assert the size and align match, and neither
|
||||
// type has any special invariants.
|
||||
unsafe { &*(self as *const Self as *const ImColor32Fields) }
|
||||
}
|
||||
}
|
||||
impl core::ops::DerefMut for ImColor32 {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut ImColor32Fields {
|
||||
// Safety: we statically assert the size and align match, and neither
|
||||
// type has any special invariants.
|
||||
unsafe { &mut *(self as *mut Self as *mut ImColor32Fields) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImColor32> for u32 {
|
||||
#[inline]
|
||||
fn from(color: ImColor32) -> Self {
|
||||
color.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for ImColor32 {
|
||||
#[inline]
|
||||
fn from(color: u32) -> Self {
|
||||
ImColor32(color)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[f32; 4]> for ImColor32 {
|
||||
#[inline]
|
||||
fn from(v: [f32; 4]) -> Self {
|
||||
Self::from_rgba_f32s(v[0], v[1], v[2], v[3])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(f32, f32, f32, f32)> for ImColor32 {
|
||||
#[inline]
|
||||
fn from(v: (f32, f32, f32, f32)) -> Self {
|
||||
Self::from_rgba_f32s(v.0, v.1, v.2, v.3)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[f32; 3]> for ImColor32 {
|
||||
#[inline]
|
||||
fn from(v: [f32; 3]) -> Self {
|
||||
Self::from_rgb_f32s(v[0], v[1], v[2])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(f32, f32, f32)> for ImColor32 {
|
||||
fn from(v: (f32, f32, f32)) -> Self {
|
||||
Self::from_rgb_f32s(v.0, v.1, v.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImColor32> for [f32; 4] {
|
||||
#[inline]
|
||||
fn from(v: ImColor32) -> Self {
|
||||
v.to_rgba_f32s()
|
||||
}
|
||||
}
|
||||
impl From<ImColor32> for (f32, f32, f32, f32) {
|
||||
#[inline]
|
||||
fn from(color: ImColor32) -> Self {
|
||||
let [r, g, b, a]: [f32; 4] = color.into();
|
||||
(r, g, b, a)
|
||||
}
|
||||
}
|
||||
|
||||
// These utilities might be worth making `pub` as free functions in
|
||||
// `crate::color` so user code can ensure their numeric handling is
|
||||
// consistent...
|
||||
|
||||
/// Clamp `v` to between 0.0 and 1.0, always returning a value between those.
|
||||
///
|
||||
/// Never returns NaN, or -0.0 — instead returns +0.0 for these (We differ from
|
||||
/// C++ Dear ImGUI here which probably is just ignoring values like these).
|
||||
#[inline]
|
||||
pub(crate) fn saturate(v: f32) -> f32 {
|
||||
// Note: written strangely so that special values (NaN/-0.0) are handled
|
||||
// automatically with no extra checks.
|
||||
if v > 0.0 {
|
||||
if v <= 1.0 {
|
||||
v
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Quantize a value in `0.0..=1.0` to `0..=u8::MAX`. Input outside 0.0..=1.0 is
|
||||
/// clamped. Uses a bias of 0.5, because we assume centered quantization is used
|
||||
/// (and because C++ imgui does it too). See:
|
||||
/// - https://github.com/ocornut/imgui/blob/e28b51786eae60f32c18214658c15952639085a2/imgui_internal.h#L218
|
||||
/// - https://cbloomrants.blogspot.com/2020/09/topics-in-quantization-for-games.html
|
||||
/// (see `quantize_centered`)
|
||||
#[inline]
|
||||
pub(crate) fn f32_to_u8_sat(f: f32) -> u8 {
|
||||
let f = saturate(f) * 255.0 + 0.5;
|
||||
// Safety: `saturate`'s result is between 0.0 and 1.0 (never NaN even for
|
||||
// NaN input), and so for all inputs, `saturate(f) * 255.0 + 0.5` is inside
|
||||
// `0.5 ..= 255.5`.
|
||||
//
|
||||
// This is verified for all f32 in `test_f32_to_u8_sat_exhaustive`.
|
||||
//
|
||||
// Also note that LLVM doesn't bother trying to figure this out so the
|
||||
// unchecked does actually help. (That said, this likely doesn't matter
|
||||
// for imgui-rs, but I had this code in another project and it felt
|
||||
// silly to needlessly pessimize it).
|
||||
unsafe { f.to_int_unchecked() }
|
||||
}
|
||||
|
||||
/// Opposite of `f32_to_u8_sat`. Since we assume centered quantization, this is
|
||||
/// equivalent to dividing by 255 (or, multiplying by 1.0/255.0)
|
||||
#[inline]
|
||||
pub(crate) fn u8_to_f32_sat(u: u8) -> f32 {
|
||||
(u as f32) * (1.0 / 255.0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_sat() {
|
||||
assert_eq!(saturate(1.0), 1.0);
|
||||
assert_eq!(saturate(0.5), 0.5);
|
||||
assert_eq!(saturate(0.0), 0.0);
|
||||
assert_eq!(saturate(-1.0), 0.0);
|
||||
// next float from 1.0
|
||||
assert_eq!(saturate(1.0 + f32::EPSILON), 1.0);
|
||||
// prev float from 0.0 (Well, from -0.0)
|
||||
assert_eq!(saturate(-f32::MIN_POSITIVE), 0.0);
|
||||
// some NaNs.
|
||||
assert_eq!(saturate(f32::NAN), 0.0);
|
||||
assert_eq!(saturate(-f32::NAN), 0.0);
|
||||
// neg zero comes through as +0
|
||||
assert_eq!(saturate(-0.0).to_bits(), 0.0f32.to_bits());
|
||||
}
|
||||
|
||||
// Check that the unsafe in `f32_to_u8_sat` is fine for all f32 (and that the
|
||||
// comments I wrote about `saturate` are actually true). This is way too slow in
|
||||
// debug mode, but finishes in ~15s on my machine for release (just this test).
|
||||
// This is tested in CI, but will only run if invoked manually with something
|
||||
// like: `cargo test -p imgui --release -- --ignored`.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_f32_to_u8_sat_exhaustive() {
|
||||
for f in (0..=u32::MAX).map(f32::from_bits) {
|
||||
let v = saturate(f);
|
||||
assert!(
|
||||
(0.0..=1.0).contains(&v) && (v.to_bits() != (-0.0f32).to_bits()),
|
||||
"sat({} [e.g. {:#x}]) => {} [e.g {:#x}]",
|
||||
f,
|
||||
f.to_bits(),
|
||||
v,
|
||||
v.to_bits(),
|
||||
);
|
||||
let sat = v * 255.0 + 0.5;
|
||||
// Note: This checks what's required by is the safety predicate for
|
||||
// `f32::to_int_unchecked`:
|
||||
// https://doc.rust-lang.org/std/primitive.f32.html#method.to_int_unchecked
|
||||
assert!(
|
||||
sat.trunc() >= 0.0 && sat.trunc() <= (u8::MAX as f32) && sat.is_finite(),
|
||||
"f32_to_u8_sat({} [e.g. {:#x}]) would be UB!",
|
||||
f,
|
||||
f.to_bits(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_saturate_all_u8s() {
|
||||
for u in 0..=u8::MAX {
|
||||
let v = f32_to_u8_sat(u8_to_f32_sat(u));
|
||||
assert_eq!(u, v);
|
||||
}
|
||||
}
|
||||
68
plugins/libimhex-rust/imgui-rs/src/columns.rs
vendored
Normal file
68
plugins/libimhex-rust/imgui-rs/src/columns.rs
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
/// # Columns
|
||||
impl<'ui> Ui<'ui> {
|
||||
#[doc(alias = "Columns")]
|
||||
pub fn columns(&self, count: i32, id: impl AsRef<str>, border: bool) {
|
||||
unsafe { sys::igColumns(count, self.scratch_txt(id), border) }
|
||||
}
|
||||
/// Switches to the next column.
|
||||
///
|
||||
/// If the current row is finished, switches to first column of the next row
|
||||
#[doc(alias = "NextColumn")]
|
||||
pub fn next_column(&self) {
|
||||
unsafe { sys::igNextColumn() }
|
||||
}
|
||||
/// Returns the index of the current column
|
||||
#[doc(alias = "GetColumnIndex")]
|
||||
pub fn current_column_index(&self) -> i32 {
|
||||
unsafe { sys::igGetColumnIndex() }
|
||||
}
|
||||
/// Returns the width of the current column (in pixels)
|
||||
#[doc(alias = "GetColumnWidth")]
|
||||
pub fn current_column_width(&self) -> f32 {
|
||||
unsafe { sys::igGetColumnWidth(-1) }
|
||||
}
|
||||
#[doc(alias = "GetColumnWidth")]
|
||||
/// Returns the width of the given column (in pixels)
|
||||
pub fn column_width(&self, column_index: i32) -> f32 {
|
||||
unsafe { sys::igGetColumnWidth(column_index) }
|
||||
}
|
||||
#[doc(alias = "SetColumnWidth")]
|
||||
/// Sets the width of the current column (in pixels)
|
||||
pub fn set_current_column_width(&self, width: f32) {
|
||||
unsafe { sys::igSetColumnWidth(-1, width) };
|
||||
}
|
||||
#[doc(alias = "SetColumnWidth")]
|
||||
/// Sets the width of the given column (in pixels)
|
||||
pub fn set_column_width(&self, column_index: i32, width: f32) {
|
||||
unsafe { sys::igSetColumnWidth(column_index, width) };
|
||||
}
|
||||
/// Returns the offset of the current column (in pixels from the left side of the content
|
||||
/// region)
|
||||
#[doc(alias = "GetColumnOffset")]
|
||||
pub fn current_column_offset(&self) -> f32 {
|
||||
unsafe { sys::igGetColumnOffset(-1) }
|
||||
}
|
||||
/// Returns the offset of the given column (in pixels from the left side of the content region)
|
||||
#[doc(alias = "GetColumnOffset")]
|
||||
pub fn column_offset(&self, column_index: i32) -> f32 {
|
||||
unsafe { sys::igGetColumnOffset(column_index) }
|
||||
}
|
||||
/// Sets the offset of the current column (in pixels from the left side of the content region)
|
||||
#[doc(alias = "SetColumnOffset")]
|
||||
pub fn set_current_column_offset(&self, offset_x: f32) {
|
||||
unsafe { sys::igSetColumnOffset(-1, offset_x) };
|
||||
}
|
||||
/// Sets the offset of the given column (in pixels from the left side of the content region)
|
||||
#[doc(alias = "SetColumnOffset")]
|
||||
pub fn set_column_offset(&self, column_index: i32, offset_x: f32) {
|
||||
unsafe { sys::igSetColumnOffset(column_index, offset_x) };
|
||||
}
|
||||
/// Returns the current amount of columns
|
||||
#[doc(alias = "GetColumnCount")]
|
||||
pub fn column_count(&self) -> i32 {
|
||||
unsafe { sys::igGetColumnsCount() }
|
||||
}
|
||||
}
|
||||
582
plugins/libimhex-rust/imgui-rs/src/context.rs
vendored
Normal file
582
plugins/libimhex-rust/imgui-rs/src/context.rs
vendored
Normal file
@@ -0,0 +1,582 @@
|
||||
use parking_lot::ReentrantMutex;
|
||||
use std::cell::{RefCell, UnsafeCell};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::Drop;
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::clipboard::{ClipboardBackend, ClipboardContext};
|
||||
use crate::fonts::atlas::{FontAtlas, FontAtlasRefMut, FontId, SharedFontAtlas};
|
||||
use crate::io::Io;
|
||||
use crate::style::Style;
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
/// An imgui-rs context.
|
||||
///
|
||||
/// A context needs to be created to access most library functions. Due to current Dear ImGui
|
||||
/// design choices, at most one active Context can exist at any time. This limitation will likely
|
||||
/// be removed in a future Dear ImGui version.
|
||||
///
|
||||
/// If you need more than one context, you can use suspended contexts. As long as only one context
|
||||
/// is active at a time, it's possible to have multiple independent contexts.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Creating a new active context:
|
||||
/// ```
|
||||
/// let ctx = imgui::Context::create();
|
||||
/// // ctx is dropped naturally when it goes out of scope, which deactivates and destroys the
|
||||
/// // context
|
||||
/// ```
|
||||
///
|
||||
/// Never try to create an active context when another one is active:
|
||||
///
|
||||
/// ```should_panic
|
||||
/// let ctx1 = imgui::Context::create();
|
||||
///
|
||||
/// let ctx2 = imgui::Context::create(); // PANIC
|
||||
/// ```
|
||||
///
|
||||
/// Suspending an active context allows you to create another active context:
|
||||
///
|
||||
/// ```
|
||||
/// let ctx1 = imgui::Context::create();
|
||||
/// let suspended1 = ctx1.suspend();
|
||||
/// let ctx2 = imgui::Context::create(); // this is now OK
|
||||
/// ```
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Context {
|
||||
raw: *mut sys::ImGuiContext,
|
||||
shared_font_atlas: Option<Rc<RefCell<SharedFontAtlas>>>,
|
||||
ini_filename: Option<CString>,
|
||||
log_filename: Option<CString>,
|
||||
platform_name: Option<CString>,
|
||||
renderer_name: Option<CString>,
|
||||
// we need to box this because we hand imgui a pointer to it,
|
||||
// and we don't want to deal with finding `clipboard_ctx`.
|
||||
// we also put it in an unsafecell since we're going to give
|
||||
// imgui a mutable pointer to it.
|
||||
clipboard_ctx: Box<UnsafeCell<ClipboardContext>>,
|
||||
}
|
||||
|
||||
// This mutex needs to be used to guard all public functions that can affect the underlying
|
||||
// Dear ImGui active context
|
||||
static CTX_MUTEX: ReentrantMutex<()> = parking_lot::const_reentrant_mutex(());
|
||||
|
||||
fn clear_current_context() {
|
||||
unsafe {
|
||||
sys::igSetCurrentContext(ptr::null_mut());
|
||||
}
|
||||
}
|
||||
fn no_current_context() -> bool {
|
||||
let ctx = unsafe { sys::igGetCurrentContext() };
|
||||
ctx.is_null()
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Creates a new active imgui-rs context.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if an active context already exists
|
||||
#[doc(alias = "CreateContext")]
|
||||
pub fn create() -> Self {
|
||||
Self::create_internal(None)
|
||||
}
|
||||
/// Creates a new active imgui-rs context with a shared font atlas.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if an active context already exists
|
||||
#[doc(alias = "CreateContext")]
|
||||
pub fn create_with_shared_font_atlas(shared_font_atlas: Rc<RefCell<SharedFontAtlas>>) -> Self {
|
||||
Self::create_internal(Some(shared_font_atlas))
|
||||
}
|
||||
/// Suspends this context so another context can be the active context.
|
||||
#[doc(alias = "CreateContext")]
|
||||
pub fn suspend(self) -> SuspendedContext {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
assert!(
|
||||
self.is_current_context(),
|
||||
"context to be suspended is not the active context"
|
||||
);
|
||||
clear_current_context();
|
||||
SuspendedContext(self)
|
||||
}
|
||||
/// Returns the path to the ini file, or None if not set
|
||||
pub fn ini_filename(&self) -> Option<PathBuf> {
|
||||
let io = self.io();
|
||||
if io.ini_filename.is_null() {
|
||||
None
|
||||
} else {
|
||||
let s = unsafe { CStr::from_ptr(io.ini_filename) };
|
||||
Some(PathBuf::from(s.to_str().ok()?))
|
||||
}
|
||||
}
|
||||
/// Sets the path to the ini file (default is "imgui.ini")
|
||||
///
|
||||
/// Pass None to disable automatic .Ini saving.
|
||||
pub fn set_ini_filename<T: Into<Option<PathBuf>>>(&mut self, ini_filename: T) {
|
||||
let ini_filename: Option<PathBuf> = ini_filename.into();
|
||||
let ini_filename = ini_filename.and_then(|v| CString::new(v.to_str()?).ok());
|
||||
|
||||
self.io_mut().ini_filename = ini_filename
|
||||
.as_ref()
|
||||
.map(|x| x.as_ptr())
|
||||
.unwrap_or(ptr::null());
|
||||
self.ini_filename = ini_filename;
|
||||
}
|
||||
/// Returns the path to the log file, or None if not set
|
||||
// TODO: why do we return an `Option<PathBuf>` instead of an `Option<&Path>`?
|
||||
pub fn log_filename(&self) -> Option<PathBuf> {
|
||||
let io = self.io();
|
||||
if io.log_filename.is_null() {
|
||||
None
|
||||
} else {
|
||||
let cstr = unsafe { CStr::from_ptr(io.log_filename) };
|
||||
Some(PathBuf::from(cstr.to_str().ok()?))
|
||||
}
|
||||
}
|
||||
/// Sets the log filename (default is "imgui_log.txt").
|
||||
pub fn set_log_filename<T: Into<Option<PathBuf>>>(&mut self, log_filename: T) {
|
||||
let log_filename = log_filename
|
||||
.into()
|
||||
.and_then(|v| CString::new(v.to_str()?).ok());
|
||||
|
||||
self.io_mut().log_filename = log_filename
|
||||
.as_ref()
|
||||
.map(|x| x.as_ptr())
|
||||
.unwrap_or(ptr::null());
|
||||
self.log_filename = log_filename;
|
||||
}
|
||||
/// Returns the backend platform name, or None if not set
|
||||
pub fn platform_name(&self) -> Option<&str> {
|
||||
let io = self.io();
|
||||
if io.backend_platform_name.is_null() {
|
||||
None
|
||||
} else {
|
||||
let cstr = unsafe { CStr::from_ptr(io.backend_platform_name) };
|
||||
cstr.to_str().ok()
|
||||
}
|
||||
}
|
||||
/// Sets the backend platform name
|
||||
pub fn set_platform_name<T: Into<Option<String>>>(&mut self, platform_name: T) {
|
||||
let platform_name: Option<CString> =
|
||||
platform_name.into().and_then(|v| CString::new(v).ok());
|
||||
self.io_mut().backend_platform_name = platform_name
|
||||
.as_ref()
|
||||
.map(|x| x.as_ptr())
|
||||
.unwrap_or(ptr::null());
|
||||
self.platform_name = platform_name;
|
||||
}
|
||||
/// Returns the backend renderer name, or None if not set
|
||||
pub fn renderer_name(&self) -> Option<&str> {
|
||||
let io = self.io();
|
||||
if io.backend_renderer_name.is_null() {
|
||||
None
|
||||
} else {
|
||||
let cstr = unsafe { CStr::from_ptr(io.backend_renderer_name) };
|
||||
cstr.to_str().ok()
|
||||
}
|
||||
}
|
||||
/// Sets the backend renderer name
|
||||
pub fn set_renderer_name<T: Into<Option<String>>>(&mut self, renderer_name: T) {
|
||||
let renderer_name: Option<CString> =
|
||||
renderer_name.into().and_then(|v| CString::new(v).ok());
|
||||
|
||||
self.io_mut().backend_renderer_name = renderer_name
|
||||
.as_ref()
|
||||
.map(|x| x.as_ptr())
|
||||
.unwrap_or(ptr::null());
|
||||
|
||||
self.renderer_name = renderer_name;
|
||||
}
|
||||
/// Loads settings from a string slice containing settings in .Ini file format
|
||||
#[doc(alias = "LoadIniSettingsFromMemory")]
|
||||
pub fn load_ini_settings(&mut self, data: &str) {
|
||||
unsafe { sys::igLoadIniSettingsFromMemory(data.as_ptr() as *const _, data.len()) }
|
||||
}
|
||||
/// Saves settings to a mutable string buffer in .Ini file format
|
||||
#[doc(alias = "SaveInitSettingsToMemory")]
|
||||
pub fn save_ini_settings(&mut self, buf: &mut String) {
|
||||
let data = unsafe { CStr::from_ptr(sys::igSaveIniSettingsToMemory(ptr::null_mut())) };
|
||||
buf.push_str(&data.to_string_lossy());
|
||||
}
|
||||
/// Sets the clipboard backend used for clipboard operations
|
||||
pub fn set_clipboard_backend<T: ClipboardBackend>(&mut self, backend: T) {
|
||||
let clipboard_ctx: Box<UnsafeCell<_>> = Box::new(ClipboardContext::new(backend).into());
|
||||
let io = self.io_mut();
|
||||
io.set_clipboard_text_fn = Some(crate::clipboard::set_clipboard_text);
|
||||
io.get_clipboard_text_fn = Some(crate::clipboard::get_clipboard_text);
|
||||
|
||||
io.clipboard_user_data = clipboard_ctx.get() as *mut _;
|
||||
self.clipboard_ctx = clipboard_ctx;
|
||||
}
|
||||
fn create_internal(shared_font_atlas: Option<Rc<RefCell<SharedFontAtlas>>>) -> Self {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
assert!(
|
||||
no_current_context(),
|
||||
"A new active context cannot be created, because another one already exists"
|
||||
);
|
||||
|
||||
let shared_font_atlas_ptr = match &shared_font_atlas {
|
||||
Some(shared_font_atlas) => {
|
||||
let borrowed_font_atlas = shared_font_atlas.borrow();
|
||||
borrowed_font_atlas.0
|
||||
}
|
||||
None => ptr::null_mut(),
|
||||
};
|
||||
// Dear ImGui implicitly sets the current context during igCreateContext if the current
|
||||
// context doesn't exist
|
||||
let raw = unsafe { sys::igCreateContext(shared_font_atlas_ptr) };
|
||||
|
||||
Context {
|
||||
raw,
|
||||
shared_font_atlas,
|
||||
ini_filename: None,
|
||||
log_filename: None,
|
||||
platform_name: None,
|
||||
renderer_name: None,
|
||||
clipboard_ctx: Box::new(ClipboardContext::dummy().into()),
|
||||
}
|
||||
}
|
||||
fn is_current_context(&self) -> bool {
|
||||
let ctx = unsafe { sys::igGetCurrentContext() };
|
||||
self.raw == ctx
|
||||
}
|
||||
|
||||
/// Get a reference to the current context
|
||||
pub fn current() -> Option<ContextRef> {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
|
||||
let raw = unsafe { sys::igGetCurrentContext() };
|
||||
|
||||
if raw.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(ContextRef(ManuallyDrop::new(Context {
|
||||
raw,
|
||||
shared_font_atlas: None, // XXX: this might be needed tbh
|
||||
ini_filename: None,
|
||||
log_filename: None,
|
||||
platform_name: None,
|
||||
renderer_name: None,
|
||||
clipboard_ctx: Box::new(ClipboardContext::dummy().into()),
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A reference to a [`Context`] object
|
||||
#[derive(Debug)]
|
||||
pub struct ContextRef(ManuallyDrop<Context>);
|
||||
|
||||
impl core::ops::Deref for ContextRef {
|
||||
type Target = Context;
|
||||
|
||||
fn deref(&self) -> &Context {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::DerefMut for ContextRef {
|
||||
fn deref_mut(&mut self) -> &mut Context {
|
||||
&mut *self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Context {
|
||||
#[doc(alias = "DestroyContext")]
|
||||
fn drop(&mut self) {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
// If this context is the active context, Dear ImGui automatically deactivates it during
|
||||
// destruction
|
||||
unsafe {
|
||||
sys::igDestroyContext(self.raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A suspended imgui-rs context.
|
||||
///
|
||||
/// A suspended context retains its state, but is not usable without activating it first.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Suspended contexts are not directly very useful, but you can activate them:
|
||||
///
|
||||
/// ```
|
||||
/// let suspended = imgui::SuspendedContext::create();
|
||||
/// match suspended.activate() {
|
||||
/// Ok(ctx) => {
|
||||
/// // ctx is now the active context
|
||||
/// },
|
||||
/// Err(suspended) => {
|
||||
/// // activation failed, so you get the suspended context back
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct SuspendedContext(Context);
|
||||
|
||||
impl SuspendedContext {
|
||||
/// Creates a new suspended imgui-rs context.
|
||||
#[doc(alias = "CreateContext")]
|
||||
pub fn create() -> Self {
|
||||
Self::create_internal(None)
|
||||
}
|
||||
/// Creates a new suspended imgui-rs context with a shared font atlas.
|
||||
pub fn create_with_shared_font_atlas(shared_font_atlas: Rc<RefCell<SharedFontAtlas>>) -> Self {
|
||||
Self::create_internal(Some(shared_font_atlas))
|
||||
}
|
||||
/// Attempts to activate this suspended context.
|
||||
///
|
||||
/// If there is no active context, this suspended context is activated and `Ok` is returned,
|
||||
/// containing the activated context.
|
||||
/// If there is already an active context, nothing happens and `Err` is returned, containing
|
||||
/// the original suspended context.
|
||||
#[doc(alias = "SetCurrentContext")]
|
||||
pub fn activate(self) -> Result<Context, SuspendedContext> {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
if no_current_context() {
|
||||
unsafe {
|
||||
sys::igSetCurrentContext(self.0.raw);
|
||||
}
|
||||
Ok(self.0)
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
fn create_internal(shared_font_atlas: Option<Rc<RefCell<SharedFontAtlas>>>) -> Self {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
let raw = unsafe { sys::igCreateContext(ptr::null_mut()) };
|
||||
let ctx = Context {
|
||||
raw,
|
||||
shared_font_atlas,
|
||||
ini_filename: None,
|
||||
log_filename: None,
|
||||
platform_name: None,
|
||||
renderer_name: None,
|
||||
clipboard_ctx: Box::new(ClipboardContext::dummy().into()),
|
||||
};
|
||||
if ctx.is_current_context() {
|
||||
// Oops, the context was activated -> deactivate
|
||||
clear_current_context();
|
||||
}
|
||||
SuspendedContext(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_one_context() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let _ctx = Context::create();
|
||||
assert!(!no_current_context());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drop_clears_current_context() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
{
|
||||
let _ctx1 = Context::create();
|
||||
assert!(!no_current_context());
|
||||
}
|
||||
assert!(no_current_context());
|
||||
{
|
||||
let _ctx2 = Context::create();
|
||||
assert!(!no_current_context());
|
||||
}
|
||||
assert!(no_current_context());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_suspended() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let ctx = Context::create();
|
||||
let _suspended = SuspendedContext::create();
|
||||
assert!(ctx.is_current_context());
|
||||
::std::mem::drop(_suspended);
|
||||
assert!(ctx.is_current_context());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suspend() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let ctx = Context::create();
|
||||
assert!(!no_current_context());
|
||||
let _suspended = ctx.suspend();
|
||||
assert!(no_current_context());
|
||||
let _ctx2 = Context::create();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drop_suspended() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let suspended = Context::create().suspend();
|
||||
assert!(no_current_context());
|
||||
let ctx2 = Context::create();
|
||||
::std::mem::drop(suspended);
|
||||
assert!(ctx2.is_current_context());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suspend_activate() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let suspended = Context::create().suspend();
|
||||
assert!(no_current_context());
|
||||
let ctx = suspended.activate().unwrap();
|
||||
assert!(ctx.is_current_context());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suspend_failure() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let suspended = Context::create().suspend();
|
||||
let _ctx = Context::create();
|
||||
assert!(suspended.activate().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shared_font_atlas() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let atlas = Rc::new(RefCell::new(SharedFontAtlas::create()));
|
||||
let suspended1 = SuspendedContext::create_with_shared_font_atlas(atlas.clone());
|
||||
let mut ctx2 = Context::create_with_shared_font_atlas(atlas);
|
||||
{
|
||||
let _borrow = ctx2.fonts();
|
||||
}
|
||||
let _suspended2 = ctx2.suspend();
|
||||
let mut ctx = suspended1.activate().unwrap();
|
||||
let _borrow = ctx.fonts();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_shared_font_atlas_borrow_panic() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let atlas = Rc::new(RefCell::new(SharedFontAtlas::create()));
|
||||
let _suspended = SuspendedContext::create_with_shared_font_atlas(atlas.clone());
|
||||
let mut ctx = Context::create_with_shared_font_atlas(atlas.clone());
|
||||
let _borrow1 = atlas.borrow();
|
||||
let _borrow2 = ctx.fonts();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ini_load_save() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx();
|
||||
let data = "[Window][Debug##Default]
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0";
|
||||
ctx.load_ini_settings(data);
|
||||
let mut buf = String::new();
|
||||
ctx.save_ini_settings(&mut buf);
|
||||
assert_eq!(data.trim(), buf.trim());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_ini_filename() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let ctx = Context::create();
|
||||
assert_eq!(ctx.ini_filename(), Some(PathBuf::from("imgui.ini")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_ini_filename() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx();
|
||||
ctx.set_ini_filename(Some(PathBuf::from("test.ini")));
|
||||
assert_eq!(ctx.ini_filename(), Some(PathBuf::from("test.ini")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_log_filename() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let ctx = Context::create();
|
||||
assert_eq!(ctx.log_filename(), Some(PathBuf::from("imgui_log.txt")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_log_filename() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx();
|
||||
ctx.set_log_filename(Some(PathBuf::from("test.log")));
|
||||
assert_eq!(ctx.log_filename(), Some(PathBuf::from("test.log")));
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Returns an immutable reference to the inputs/outputs object
|
||||
pub fn io(&self) -> &Io {
|
||||
unsafe {
|
||||
// safe because Io is a transparent wrapper around sys::ImGuiIO
|
||||
&*(sys::igGetIO() as *const Io)
|
||||
}
|
||||
}
|
||||
/// Returns a mutable reference to the inputs/outputs object
|
||||
pub fn io_mut(&mut self) -> &mut Io {
|
||||
unsafe {
|
||||
// safe because Io is a transparent wrapper around sys::ImGuiIO
|
||||
&mut *(sys::igGetIO() as *mut Io)
|
||||
}
|
||||
}
|
||||
/// Returns an immutable reference to the user interface style
|
||||
#[doc(alias = "GetStyle")]
|
||||
pub fn style(&self) -> &Style {
|
||||
unsafe {
|
||||
// safe because Style is a transparent wrapper around sys::ImGuiStyle
|
||||
&*(sys::igGetStyle() as *const Style)
|
||||
}
|
||||
}
|
||||
/// Returns a mutable reference to the user interface style
|
||||
#[doc(alias = "GetStyle")]
|
||||
pub fn style_mut(&mut self) -> &mut Style {
|
||||
unsafe {
|
||||
// safe because Style is a transparent wrapper around sys::ImGuiStyle
|
||||
&mut *(sys::igGetStyle() as *mut Style)
|
||||
}
|
||||
}
|
||||
/// Returns a mutable reference to the font atlas.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the context uses a shared font atlas that is already borrowed
|
||||
pub fn fonts(&mut self) -> FontAtlasRefMut<'_> {
|
||||
match self.shared_font_atlas {
|
||||
Some(ref font_atlas) => FontAtlasRefMut::Shared(font_atlas.borrow_mut()),
|
||||
None => unsafe {
|
||||
// safe because FontAtlas is a transparent wrapper around sys::ImFontAtlas
|
||||
let fonts = &mut *(self.io_mut().fonts as *mut FontAtlas);
|
||||
FontAtlasRefMut::Owned(fonts)
|
||||
},
|
||||
}
|
||||
}
|
||||
/// Starts a new frame and returns an `Ui` instance for constructing a user interface.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the context uses a shared font atlas that is already borrowed
|
||||
#[doc(alias = "NewFame")]
|
||||
pub fn frame(&mut self) -> Ui<'_> {
|
||||
// Clear default font if it no longer exists. This could be an error in the future
|
||||
let default_font = self.io().font_default;
|
||||
if !default_font.is_null() && self.fonts().get_font(FontId(default_font)).is_none() {
|
||||
self.io_mut().font_default = ptr::null_mut();
|
||||
}
|
||||
// NewFrame/Render/EndFrame mutate the font atlas so we need exclusive access to it
|
||||
let font_atlas = self
|
||||
.shared_font_atlas
|
||||
.as_ref()
|
||||
.map(|font_atlas| font_atlas.borrow_mut());
|
||||
// TODO: precondition checks
|
||||
unsafe {
|
||||
sys::igNewFrame();
|
||||
}
|
||||
Ui {
|
||||
ctx: self,
|
||||
font_atlas,
|
||||
buffer: crate::UiBuffer::new(1024).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
594
plugins/libimhex-rust/imgui-rs/src/drag_drop.rs
vendored
Normal file
594
plugins/libimhex-rust/imgui-rs/src/drag_drop.rs
vendored
Normal file
@@ -0,0 +1,594 @@
|
||||
//! Structs to create a Drag and Drop sequence. Almost all structs are re-exported
|
||||
//! and can be accessed from the crate root; some additional utilities can be found in here.
|
||||
//!
|
||||
//! A DragDrop is a UI mechanism where users can appear to "drag"
|
||||
//! some data from one [source](DragDropSource) to one [target](DragDropTarget).
|
||||
//! A source and a target must both have some `name` identifier, which is declared when they
|
||||
//! are created. If these names are equal, then a `payload` of some kind
|
||||
//! will be given to the target caller whne the user releases their mouse button over
|
||||
//! the target (additionally, the UI will reflect that the payload *can* be deposited
|
||||
//! in the target).
|
||||
//!
|
||||
//! The complexity of this implementation is primarily in managing this payload. Users
|
||||
//! can provide three different kinds of payloads:
|
||||
//!
|
||||
//! 1. Users can give an [empty payload](DragDropPayloadEmpty) with [begin](DragDropSource::begin).
|
||||
//! This payload type is essentially just a notification system, but using some shared state,
|
||||
//! this can be reasonably powerful, and is the safest way to transfer non-Copy data offered
|
||||
//! right now.
|
||||
//! 2. Users can give a [simple Copy payload](DragDropPayloadPod) with [begin](DragDropSource::begin_payload).
|
||||
//! This allows users to copy data to Dear ImGui, which will take ownership over it, and then be given
|
||||
//! it back to the Target. Please note: users are of course free to not drop any drag (cancel a drag),
|
||||
//! so this data could easily be lost forever. Our `'static + Copy` bound is intended to keep users
|
||||
//! to simplistic types.
|
||||
//! 3. An unsafe implementation is provided which allows for any data to be unsafely copied. Note that once
|
||||
//! you use this method, the safe implementations in #1 and #2 can create memory unsafety problems; notably,
|
||||
//! they both assume that a payload has certain header information within it.
|
||||
//!
|
||||
//! For examples of each payload type, see [DragDropSource].
|
||||
use std::{any, ffi, marker::PhantomData};
|
||||
|
||||
use crate::{sys, Condition, Ui};
|
||||
use bitflags::bitflags;
|
||||
|
||||
bitflags!(
|
||||
/// Flags for igBeginDragDropSource(), igAcceptDragDropPayload()
|
||||
#[repr(transparent)]
|
||||
pub struct DragDropFlags: u32 {
|
||||
/// By default, a successful call to igBeginDragDropSource opens a tooltip so you can
|
||||
/// display a preview or description of the source contents. This flag disable this
|
||||
/// behavior.
|
||||
const SOURCE_NO_PREVIEW_TOOLTIP = sys::ImGuiDragDropFlags_SourceNoPreviewTooltip;
|
||||
/// By default, when dragging we clear data so that igIsItemHovered() will return false, to
|
||||
/// avoid subsequent user code submitting tooltips. This flag disable this behavior so you
|
||||
/// can still call igIsItemHovered() on the source item.
|
||||
const SOURCE_NO_DISABLE_HOVER = sys::ImGuiDragDropFlags_SourceNoDisableHover;
|
||||
/// Disable the behavior that allows to open tree nodes and collapsing header by holding
|
||||
/// over them while dragging a source item.
|
||||
const SOURCE_NO_HOLD_TO_OPEN_OTHERS = sys::ImGuiDragDropFlags_SourceNoHoldToOpenOthers;
|
||||
/// Allow items such as igText(), igImage() that have no unique identifier to be used as
|
||||
/// drag source, by manufacturing a temporary identifier based on their window-relative
|
||||
/// position. This is extremely unusual within the dear imgui ecosystem and so we made it
|
||||
/// explicit.
|
||||
const SOURCE_ALLOW_NULL_ID = sys::ImGuiDragDropFlags_SourceAllowNullID;
|
||||
/// External source (from outside of imgui), won't attempt to read current item/window
|
||||
/// info. Will always return true. Only one Extern source can be active simultaneously.
|
||||
const SOURCE_EXTERN = sys::ImGuiDragDropFlags_SourceExtern;
|
||||
/// Automatically expire the payload if the source ceases to be submitted (otherwise
|
||||
/// payloads are persisting while being dragged)
|
||||
const SOURCE_AUTO_EXPIRE_PAYLOAD = sys::ImGuiDragDropFlags_SourceAutoExpirePayload;
|
||||
/// igAcceptDragDropPayload() will returns true even before the mouse button is released.
|
||||
/// You can then call igIsDelivery() to test if the payload needs to be delivered.
|
||||
const ACCEPT_BEFORE_DELIVERY = sys::ImGuiDragDropFlags_AcceptBeforeDelivery;
|
||||
/// Do not draw the default highlight rectangle when hovering over target.
|
||||
const ACCEPT_NO_DRAW_DEFAULT_RECT = sys::ImGuiDragDropFlags_AcceptNoDrawDefaultRect;
|
||||
/// Request hiding the igBeginDragDropSource tooltip from the igBeginDragDropTarget site.
|
||||
const ACCEPT_NO_PREVIEW_TOOLTIP = sys::ImGuiDragDropFlags_AcceptNoPreviewTooltip;
|
||||
/// For peeking ahead and inspecting the payload before delivery. This is just a convenience
|
||||
/// flag for the intersection of `ACCEPT_BEFORE_DELIVERY` and `ACCEPT_NO_DRAW_DEFAULT_RECT`
|
||||
const ACCEPT_PEEK_ONLY = sys::ImGuiDragDropFlags_AcceptPeekOnly;
|
||||
}
|
||||
);
|
||||
|
||||
/// Creates a source for drag drop data out of the last ID created.
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// fn show_ui(ui: &Ui<'_>) {
|
||||
/// ui.button("Hello, I am a drag source!");
|
||||
///
|
||||
/// // Creates an empty DragSource with no tooltip
|
||||
/// DragDropSource::new("BUTTON_DRAG").begin(ui);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Notice especially the `"BUTTON_DRAG"` name -- this is the identifier of this
|
||||
/// DragDropSource; [DragDropTarget]'s will specify an identifier to *receive*, and these
|
||||
/// names must match up. A single item should only have one [DragDropSource], though
|
||||
/// a target may have multiple different targets.
|
||||
///
|
||||
/// DropDropSources don't do anything until you use one of the three `begin_` methods
|
||||
/// on this struct. Each of these methods describes how you handle the Payload which ImGui
|
||||
/// will manage, and then give to a [DragDropTarget], which will received the payload. The
|
||||
/// simplest and safest Payload is the empty payload, created with [begin](Self::begin).
|
||||
#[derive(Debug)]
|
||||
pub struct DragDropSource<T> {
|
||||
name: T,
|
||||
flags: DragDropFlags,
|
||||
cond: Condition,
|
||||
}
|
||||
|
||||
impl<T: AsRef<str>> DragDropSource<T> {
|
||||
/// Creates a new [DragDropSource] with no flags and the `Condition::Always` with the given name.
|
||||
/// ImGui refers to this `name` field as a `type`, but really it's just an identifier to match up
|
||||
/// Source/Target for DragDrop.
|
||||
pub fn new(name: T) -> Self {
|
||||
Self {
|
||||
name,
|
||||
flags: DragDropFlags::empty(),
|
||||
cond: Condition::Always,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the flags on the [DragDropSource]. Only the flags `SOURCE_NO_PREVIEW_TOOLTIP`,
|
||||
/// `SOURCE_NO_DISABLE_HOVER`, `SOURCE_NO_HOLD_TO_OPEN_OTHERS`, `SOURCE_ALLOW_NULL_ID`,
|
||||
/// `SOURCE_EXTERN`, `SOURCE_AUTO_EXPIRE_PAYLOAD` make semantic sense, but any other flags will
|
||||
/// be accepted without panic.
|
||||
#[inline]
|
||||
pub fn flags(mut self, flags: DragDropFlags) -> Self {
|
||||
self.flags = flags;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the condition on the [DragDropSource]. Defaults to [Always](Condition::Always).
|
||||
#[inline]
|
||||
pub fn condition(mut self, cond: Condition) -> Self {
|
||||
self.cond = cond;
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates the source of a drag and returns a handle on the tooltip.
|
||||
/// This handle can be immediately dropped without binding it, in which case a default empty
|
||||
/// circle will be used for the "blank" tooltip as this item is being dragged around.
|
||||
///
|
||||
/// Otherwise, use this tooltip to add data which will display as this item is dragged.
|
||||
/// If `SOURCE_NO_PREVIEW_TOOLTIP` is enabled, however, no preview will be displayed
|
||||
/// and this returned token does nothing. Additionally, a given target may use the flag
|
||||
/// `ACCEPT_NO_PREVIEW_TOOLTIP`, which will also prevent this tooltip from being shown.
|
||||
///
|
||||
/// This drag has no payload, but is still probably the most useful way in imgui-rs to handle payloads.
|
||||
/// Using `once_cell` or some shared data, this pattern can be very powerful:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// fn show_ui(ui: &Ui<'_>, drop_message: &mut Option<String>) {
|
||||
/// ui.button("Drag me!");
|
||||
///
|
||||
/// let drag_drop_name = "Test Drag";
|
||||
///
|
||||
/// // drag drop SOURCE
|
||||
/// if DragDropSource::new(drag_drop_name).begin(ui).is_some() {
|
||||
/// // warning -- this would allocate every frame if `DragDropSource` has
|
||||
/// // condition `Always`, which it does by default. We're okay with that for
|
||||
/// // this example, but real code probably wouldn't want to allocate so much.
|
||||
/// *drop_message = Some("Test Payload".to_string());
|
||||
/// }
|
||||
///
|
||||
/// ui.button("Target me!");
|
||||
///
|
||||
/// // drag drop TARGET
|
||||
/// if let Some(target) = imgui::DragDropTarget::new(ui) {
|
||||
/// if target
|
||||
/// .accept_payload_empty(drag_drop_name, DragDropFlags::empty())
|
||||
/// .is_some()
|
||||
/// {
|
||||
/// let msg = drop_message.take().unwrap();
|
||||
/// assert_eq!(msg, "Test Payload");
|
||||
/// }
|
||||
///
|
||||
/// target.pop();
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// In the above, you'll see how the payload is really just a message passing service.
|
||||
/// If you want to pass a simple integer or other "plain old data", take a look at
|
||||
/// [begin_payload](Self::begin_payload).
|
||||
#[inline]
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<DragDropSourceToolTip<'ui>> {
|
||||
self.begin_payload(ui, ())
|
||||
}
|
||||
|
||||
/// Creates the source of a drag and returns a handle on the tooltip.
|
||||
/// This handle can be immediately dropped without binding it, in which case a default empty
|
||||
/// circle will be used for the "blank" tooltip as this item is being dragged around.
|
||||
///
|
||||
/// Otherwise, use this tooltip to add data which will display as this item is dragged.
|
||||
/// If `SOURCE_NO_PREVIEW_TOOLTIP` is enabled, however, no preview will be displayed
|
||||
/// and this returned token does nothing. Additionally, a given target may use the flag
|
||||
/// `ACCEPT_NO_PREVIEW_TOOLTIP`, which will also prevent this tooltip from being shown.
|
||||
///
|
||||
/// This function also takes a payload in the form of `T: Copy + 'static`. ImGui will
|
||||
/// memcpy this data immediately to an internally held buffer, and will return the data
|
||||
/// to [DragDropTarget].
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// fn show_ui(ui: &Ui<'_>) {
|
||||
/// ui.button("Drag me!");
|
||||
///
|
||||
/// let drag_drop_name = "Test Drag";
|
||||
/// let msg_to_send = "hello there sailor";
|
||||
///
|
||||
/// // drag drop SOURCE
|
||||
/// if let Some(tooltip) = DragDropSource::new(drag_drop_name).begin_payload(ui, msg_to_send) {
|
||||
/// ui.text("Sending message!");
|
||||
/// tooltip.end();
|
||||
/// }
|
||||
///
|
||||
/// ui.button("Target me!");
|
||||
///
|
||||
/// // drag drop TARGET
|
||||
/// if let Some(target) = imgui::DragDropTarget::new(ui) {
|
||||
/// if let Some(Ok(payload_data)) = target
|
||||
/// .accept_payload::<&'static str, _>(drag_drop_name, DragDropFlags::empty())
|
||||
/// {
|
||||
/// let msg = payload_data.data;
|
||||
/// assert_eq!(msg, msg_to_send);
|
||||
/// }
|
||||
///
|
||||
/// target.pop();
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn begin_payload<'ui, P: Copy + 'static>(
|
||||
self,
|
||||
ui: &Ui<'ui>,
|
||||
payload: P,
|
||||
) -> Option<DragDropSourceToolTip<'ui>> {
|
||||
unsafe {
|
||||
let payload = TypedPayload::new(payload);
|
||||
self.begin_payload_unchecked(
|
||||
ui,
|
||||
&payload as *const _ as *const ffi::c_void,
|
||||
std::mem::size_of::<TypedPayload<P>>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates the source of a drag and returns a handle on the tooltip.
|
||||
/// This handle can be immediately dropped without binding it, in which case a default empty
|
||||
/// circle will be used for the "blank" tooltip as this item is being dragged around.
|
||||
///
|
||||
/// Otherwise, use this tooltip to add data which will display as this item is dragged.
|
||||
/// If `SOURCE_NO_PREVIEW_TOOLTIP` is enabled, however, no preview will be displayed
|
||||
/// and this returned token does nothing. Additionally, a given target may use the flag
|
||||
/// `ACCEPT_NO_PREVIEW_TOOLTIP`, which will also prevent this tooltip from being shown.
|
||||
///
|
||||
/// This function also takes a payload of any `*const T`. ImGui will
|
||||
/// memcpy this data immediately to an internally held buffer, and will return the data
|
||||
/// to [DragDropTarget].
|
||||
///
|
||||
/// ## Safety
|
||||
/// This function itself will not cause a panic, but using it directly opts you into
|
||||
/// managing the lifetime of the pointer provided yourself. Dear ImGui will execute a memcpy on
|
||||
/// the data passed in with the size (in bytes) given, but this is, of course, just a copy,
|
||||
/// so if you pass in an `&String`, for example, the underlying String data will not be cloned,
|
||||
/// and could easily dangle if the `String` is dropped.
|
||||
///
|
||||
/// Moreover, if `Condition::Always` is set (as it is by default), you will be copying in your data
|
||||
/// every time this function is ran in your update loop, which if it involves an allocating and then
|
||||
/// handing the allocation to ImGui, would result in a significant amount of data created.
|
||||
///
|
||||
/// Overall, users should be very sure that this function is needed before they reach for it, and instead
|
||||
/// should consider either [begin](Self::begin) or [begin_payload](Self::begin_payload).
|
||||
#[inline]
|
||||
pub unsafe fn begin_payload_unchecked<'ui>(
|
||||
&self,
|
||||
ui: &Ui<'ui>,
|
||||
ptr: *const ffi::c_void,
|
||||
size: usize,
|
||||
) -> Option<DragDropSourceToolTip<'ui>> {
|
||||
let should_begin = sys::igBeginDragDropSource(self.flags.bits() as i32);
|
||||
|
||||
if should_begin {
|
||||
sys::igSetDragDropPayload(ui.scratch_txt(&self.name), ptr, size, self.cond as i32);
|
||||
|
||||
Some(DragDropSourceToolTip::push())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper struct for RAII drap-drop support.
|
||||
pub struct DragDropSourceToolTip<'ui>(PhantomData<Ui<'ui>>);
|
||||
|
||||
impl DragDropSourceToolTip<'_> {
|
||||
/// Creates a new tooltip internally.
|
||||
#[inline]
|
||||
fn push() -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
|
||||
/// Ends the tooltip directly. You could choose to simply allow this to drop
|
||||
/// by not calling this, which will also be fine.
|
||||
#[inline]
|
||||
pub fn end(self) {
|
||||
// left empty to invoke drop...
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DragDropSourceToolTip<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { sys::igEndDragDropSource() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a target for drag drop data out of the last ID created.
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// fn show_ui(ui: &Ui<'_>) {
|
||||
/// // Drop something on this button please!
|
||||
/// ui.button("Hello, I am a drag Target!");
|
||||
///
|
||||
/// if let Some(target) = DragDropTarget::new(ui) {
|
||||
/// // accepting an empty payload (which is really just raising an event)
|
||||
/// if let Some(_payload_data) = target.accept_payload_empty("BUTTON_DRAG", DragDropFlags::empty()) {
|
||||
/// println!("Nice job getting on the payload!");
|
||||
/// }
|
||||
///
|
||||
/// // and we can accept multiple, different types of payloads with one drop target.
|
||||
/// // this is a good pattern for handling different kinds of drag/drop situations with
|
||||
/// // different kinds of data in them.
|
||||
/// if let Some(Ok(payload_data)) = target.accept_payload::<usize, _>("BUTTON_ID", DragDropFlags::empty()) {
|
||||
/// println!("Our payload's data was {}", payload_data.data);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Notice especially the `"BUTTON_DRAG"` and `"BUTTON_ID"` name -- this is the identifier of this
|
||||
/// DragDropTarget; [DragDropSource]s will specify an identifier when they send a payload, and these
|
||||
/// names must match up. Notice how a target can have multiple acceptances on them -- this is a good
|
||||
/// pattern to handle multiple kinds of data which could be passed around.
|
||||
///
|
||||
/// DropDropTargets don't do anything until you use one of the three `accept_` methods
|
||||
/// on this struct. Each of these methods will spit out a _Payload struct with an increasing
|
||||
/// amount of information on the Payload. The absolute safest solution is [accept_payload_empty](Self::accept_payload_empty).
|
||||
#[derive(Debug)]
|
||||
pub struct DragDropTarget<'ui>(&'ui Ui<'ui>);
|
||||
|
||||
impl<'ui> DragDropTarget<'ui> {
|
||||
/// Creates a new DragDropTarget, holding the [Ui]'s lifetime for the duration
|
||||
/// of its existence. This is required since this struct runs some code on its Drop
|
||||
/// to end the DragDropTarget code.
|
||||
#[doc(alias = "BeginDragDropTarget")]
|
||||
pub fn new(ui: &'ui Ui<'ui>) -> Option<Self> {
|
||||
let should_begin = unsafe { sys::igBeginDragDropTarget() };
|
||||
if should_begin {
|
||||
Some(Self(ui))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Accepts an empty payload. This is the safest option for raising named events
|
||||
/// in the DragDrop API. See [DragDropSource::begin] for more information on how you
|
||||
/// might use this pattern.
|
||||
///
|
||||
/// Note: If you began this operation with `begin_payload_unchecked` it always incorrect
|
||||
/// to use this function. Use `accept_payload_unchecked` instead
|
||||
pub fn accept_payload_empty(
|
||||
&self,
|
||||
name: impl AsRef<str>,
|
||||
flags: DragDropFlags,
|
||||
) -> Option<DragDropPayloadEmpty> {
|
||||
self.accept_payload(name, flags)?
|
||||
.ok()
|
||||
.map(|payload_pod: DragDropPayloadPod<()>| DragDropPayloadEmpty {
|
||||
preview: payload_pod.preview,
|
||||
delivery: payload_pod.delivery,
|
||||
})
|
||||
}
|
||||
|
||||
/// Accepts a payload with plain old data in it. This returns a Result, since you can specify any
|
||||
/// type. The sent type must match the return type (via TypeId) to receive an `Ok`.
|
||||
///
|
||||
/// Note: If you began this operation with `begin_payload_unchecked` it always incorrect
|
||||
/// to use this function. Use `accept_payload_unchecked` instead
|
||||
pub fn accept_payload<T: 'static + Copy, Name: AsRef<str>>(
|
||||
&self,
|
||||
name: Name,
|
||||
flags: DragDropFlags,
|
||||
) -> Option<Result<DragDropPayloadPod<T>, PayloadIsWrongType>> {
|
||||
let output = unsafe { self.accept_payload_unchecked(name, flags) };
|
||||
|
||||
// convert the unsafe payload to our Result
|
||||
output.map(|unsafe_payload| {
|
||||
// sheering off the typeid...
|
||||
let received =
|
||||
unsafe { (unsafe_payload.data as *const TypedPayloadHeader).read_unaligned() };
|
||||
let expected = any::TypeId::of::<T>();
|
||||
|
||||
if received.type_id == expected {
|
||||
let data =
|
||||
unsafe { (unsafe_payload.data as *const TypedPayload<T>).read_unaligned() }
|
||||
.data;
|
||||
Ok(DragDropPayloadPod {
|
||||
data,
|
||||
preview: unsafe_payload.preview,
|
||||
delivery: unsafe_payload.delivery,
|
||||
})
|
||||
} else {
|
||||
Err(PayloadIsWrongType {
|
||||
received,
|
||||
expected: TypedPayloadHeader::new::<T>(),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Accepts a drag and drop payload which contains a raw pointer to [c_void](std::ffi::c_void)
|
||||
/// and a size in bytes. Users should generally avoid using this function
|
||||
/// if one of the safer variants is acceptable.
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// Because this pointer comes from ImGui, absolutely no promises can be made on its
|
||||
/// contents, alignment, or lifetime. Interacting with it is therefore extremely unsafe.
|
||||
/// **Important:** a special note needs to be made to the [ACCEPT_BEFORE_DELIVERY](DragDropFlags::ACCEPT_BEFORE_DELIVERY) flag --
|
||||
/// passing this flag will make this function return `Some(DragDropPayload)` **even before
|
||||
/// the user has actually "dropped" the payload by release their mouse button.**
|
||||
///
|
||||
/// In safe functions, this works just fine, since the data can be freely copied
|
||||
/// (or doesn't exist at all!). However, if you are working with your own data, you must
|
||||
/// be extremely careful with this data, as you may, effectively, only have immutable access to it.
|
||||
///
|
||||
/// Moreover, if the `DragDropSource` has also used `Condition::Once` or similar when they sent the data,
|
||||
/// ImGui will assume its data is still valid even after your preview, so corrupting that data could
|
||||
/// lead to all sorts of unsafe behvaior on ImGui's side. In summary, using this function for any data
|
||||
/// which isn't truly `Copy` or "plain old data" is difficult, and requires substantial knowledge
|
||||
/// of the various edge cases.
|
||||
pub unsafe fn accept_payload_unchecked(
|
||||
&self,
|
||||
name: impl AsRef<str>,
|
||||
flags: DragDropFlags,
|
||||
) -> Option<DragDropPayload> {
|
||||
let inner = sys::igAcceptDragDropPayload(self.0.scratch_txt(name), flags.bits() as i32);
|
||||
if inner.is_null() {
|
||||
None
|
||||
} else {
|
||||
let inner = *inner;
|
||||
|
||||
// @fixme: there are actually other fields on `inner` which I have shorn -- they're
|
||||
// considered internal to imgui (such as id of who sent this), so i've left it for
|
||||
// now this way.
|
||||
Some(DragDropPayload {
|
||||
data: inner.Data,
|
||||
size: inner.DataSize as usize,
|
||||
preview: inner.Preview,
|
||||
delivery: inner.Delivery,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Ends the current target. Ironically, this doesn't really do anything in ImGui
|
||||
/// or in imgui-rs, but it might in the future.
|
||||
pub fn pop(self) {
|
||||
// omitted...exists just to run Drop.
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DragDropTarget<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { sys::igEndDragDropTarget() }
|
||||
}
|
||||
}
|
||||
|
||||
/// An empty DragDropPayload. It has no data in it, and just includes
|
||||
/// two bools with status information.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[non_exhaustive]
|
||||
pub struct DragDropPayloadEmpty {
|
||||
/// Set when [`accept_payload_empty`](DragDropTarget::accept_payload_empty) was called
|
||||
/// and mouse has been hovering the target item.
|
||||
pub preview: bool,
|
||||
|
||||
/// Set when [`accept_payload_empty`](DragDropTarget::accept_payload_empty) was
|
||||
/// called and mouse button is released over the target item.
|
||||
pub delivery: bool,
|
||||
}
|
||||
|
||||
/// A DragDropPayload with status information and some POD, or plain old data,
|
||||
/// in it.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct DragDropPayloadPod<T: 'static + Copy> {
|
||||
/// The kind data which was requested.
|
||||
pub data: T,
|
||||
|
||||
/// Set when [`accept_payload`](DragDropTarget::accept_payload) was called
|
||||
/// and mouse has been hovering the target item.
|
||||
pub preview: bool,
|
||||
|
||||
/// Set when [`accept_payload`](DragDropTarget::accept_payload) was
|
||||
/// called and mouse button is released over the target item.
|
||||
pub delivery: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
pub struct DragDropPayload {
|
||||
/// Data which is copied and owned by ImGui. If you have accepted the payload, you can
|
||||
/// take ownership of the data; otherwise, view it immutably. Interacting with `data` is
|
||||
/// very unsafe.
|
||||
pub data: *const ffi::c_void,
|
||||
|
||||
/// The size of the data in bytes.
|
||||
pub size: usize,
|
||||
|
||||
/// Set when [`accept_payload_unchecked`](DragDropTarget::accept_payload_unchecked) was called
|
||||
/// and mouse has been hovering the target item.
|
||||
pub preview: bool,
|
||||
|
||||
/// Set when [`accept_payload_unchecked`](DragDropTarget::accept_payload_unchecked) was
|
||||
/// called and mouse button is released over the target item. If this is set to false, then you
|
||||
/// set DragDropFlags::ACCEPT_BEFORE_DELIVERY and shouldn't mutate `data`.
|
||||
pub delivery: bool,
|
||||
}
|
||||
|
||||
/// A typed payload.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
struct TypedPayload<T> {
|
||||
header: TypedPayloadHeader,
|
||||
data: T,
|
||||
}
|
||||
|
||||
impl<T: Copy + 'static> TypedPayload<T> {
|
||||
/// Creates a new typed payload which contains this data.
|
||||
fn new(data: T) -> Self {
|
||||
Self {
|
||||
header: TypedPayloadHeader::new::<T>(),
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A header for a typed payload.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
||||
#[repr(C)]
|
||||
struct TypedPayloadHeader {
|
||||
type_id: any::TypeId,
|
||||
#[cfg(debug_assertions)]
|
||||
type_name: &'static str,
|
||||
}
|
||||
|
||||
impl TypedPayloadHeader {
|
||||
#[cfg(debug_assertions)]
|
||||
fn new<T: 'static>() -> Self {
|
||||
Self {
|
||||
type_id: any::TypeId::of::<T>(),
|
||||
type_name: any::type_name::<T>(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
fn new<T: 'static>() -> Self {
|
||||
Self {
|
||||
type_id: any::TypeId::of::<T>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates that an incorrect payload type was received. It is opaque,
|
||||
/// but you can view useful information with Debug formatting when
|
||||
/// `debug_assertions` are enabled.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
||||
pub struct PayloadIsWrongType {
|
||||
expected: TypedPayloadHeader,
|
||||
received: TypedPayloadHeader,
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
impl std::fmt::Display for PayloadIsWrongType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Payload is {} -- expected {}",
|
||||
self.received.type_name, self.expected.type_name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
impl std::fmt::Display for PayloadIsWrongType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.pad("Payload is wrong type")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for PayloadIsWrongType {}
|
||||
1041
plugins/libimhex-rust/imgui-rs/src/draw_list.rs
vendored
Normal file
1041
plugins/libimhex-rust/imgui-rs/src/draw_list.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
508
plugins/libimhex-rust/imgui-rs/src/fonts/atlas.rs
vendored
Normal file
508
plugins/libimhex-rust/imgui-rs/src/fonts/atlas.rs
vendored
Normal file
@@ -0,0 +1,508 @@
|
||||
use bitflags::bitflags;
|
||||
use std::cell;
|
||||
use std::f32;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::raw::{c_int, c_uchar, c_void};
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
||||
use crate::fonts::font::Font;
|
||||
use crate::fonts::glyph_ranges::FontGlyphRanges;
|
||||
use crate::internal::{ImVector, RawCast};
|
||||
use crate::sys;
|
||||
use crate::TextureId;
|
||||
|
||||
bitflags! {
|
||||
/// Font atlas configuration flags
|
||||
#[repr(transparent)]
|
||||
pub struct FontAtlasFlags: u32 {
|
||||
/// Don't round the height to next power of two
|
||||
const NO_POWER_OF_TWO_HEIGHT = sys::ImFontAtlasFlags_NoPowerOfTwoHeight;
|
||||
/// Don't build software mouse cursors into the atlas
|
||||
const NO_MOUSE_CURSORS = sys::ImFontAtlasFlags_NoMouseCursors;
|
||||
/// Don't build thick line textures into the atlas
|
||||
const NO_BAKED_LINES = sys::ImFontAtlasFlags_NoBakedLines;
|
||||
}
|
||||
}
|
||||
|
||||
/// A font identifier
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct FontId(pub(crate) *const Font);
|
||||
|
||||
/// A font atlas that builds a single texture
|
||||
#[repr(C)]
|
||||
pub struct FontAtlas {
|
||||
/// Configuration flags
|
||||
pub flags: FontAtlasFlags,
|
||||
/// Texture identifier
|
||||
pub tex_id: TextureId,
|
||||
/// Texture width desired by user before building the atlas.
|
||||
///
|
||||
/// Must be a power-of-two. If you have many glyphs and your graphics API has texture size
|
||||
/// restrictions, you may want to increase texture width to decrease the height.
|
||||
pub tex_desired_width: i32,
|
||||
/// Padding between glyphs within texture in pixels.
|
||||
///
|
||||
/// Defaults to 1. If your rendering method doesn't rely on bilinear filtering, you may set
|
||||
/// this to 0.
|
||||
pub tex_glyph_padding: i32,
|
||||
|
||||
locked: bool,
|
||||
text_ready: bool,
|
||||
tex_pixels_use_colors: bool,
|
||||
tex_pixels_alpha8: *mut u8,
|
||||
tex_pixels_rgba32: *mut u32,
|
||||
tex_width: i32,
|
||||
tex_height: i32,
|
||||
tex_uv_scale: [f32; 2],
|
||||
tex_uv_white_pixel: [f32; 2],
|
||||
fonts: ImVector<*mut Font>,
|
||||
custom_rects: sys::ImVector_ImFontAtlasCustomRect,
|
||||
config_data: sys::ImVector_ImFontConfig,
|
||||
tex_uv_lines: [[f32; 4]; 64],
|
||||
font_builder_io: *const sys::ImFontBuilderIO,
|
||||
font_builder_flags: i32,
|
||||
pack_id_mouse_cursors: i32,
|
||||
pack_id_lines: i32,
|
||||
}
|
||||
|
||||
unsafe impl RawCast<sys::ImFontAtlas> for FontAtlas {}
|
||||
|
||||
impl FontAtlas {
|
||||
#[doc(alias = "AddFontDefault", alias = "AddFont")]
|
||||
pub fn add_font(&mut self, font_sources: &[FontSource<'_>]) -> FontId {
|
||||
let (head, tail) = font_sources.split_first().unwrap();
|
||||
let font_id = self.add_font_internal(head, false);
|
||||
for font in tail {
|
||||
self.add_font_internal(font, true);
|
||||
}
|
||||
font_id
|
||||
}
|
||||
fn add_font_internal(&mut self, font_source: &FontSource<'_>, merge_mode: bool) -> FontId {
|
||||
let mut raw_config = sys_font_config_default();
|
||||
raw_config.MergeMode = merge_mode;
|
||||
let raw_font = match font_source {
|
||||
FontSource::DefaultFontData { config } => unsafe {
|
||||
if let Some(config) = config {
|
||||
config.apply_to_raw_config(&mut raw_config, self.raw_mut());
|
||||
}
|
||||
sys::ImFontAtlas_AddFontDefault(self.raw_mut(), &raw_config)
|
||||
},
|
||||
FontSource::TtfData {
|
||||
data,
|
||||
size_pixels,
|
||||
config,
|
||||
} => {
|
||||
if let Some(config) = config {
|
||||
unsafe {
|
||||
config.apply_to_raw_config(&mut raw_config, self.raw_mut());
|
||||
}
|
||||
}
|
||||
// We can't guarantee `data` is alive when the font atlas is built, so
|
||||
// make a copy and move ownership of the data to the atlas
|
||||
let data_copy = unsafe {
|
||||
let ptr = sys::igMemAlloc(data.len()) as *mut u8;
|
||||
assert!(!ptr.is_null());
|
||||
slice::from_raw_parts_mut(ptr, data.len())
|
||||
};
|
||||
data_copy.copy_from_slice(data);
|
||||
raw_config.FontData = data_copy.as_mut_ptr() as *mut c_void;
|
||||
raw_config.FontDataSize = data_copy.len() as i32;
|
||||
raw_config.FontDataOwnedByAtlas = true;
|
||||
raw_config.SizePixels = *size_pixels;
|
||||
unsafe { sys::ImFontAtlas_AddFont(self.raw_mut(), &raw_config) }
|
||||
}
|
||||
};
|
||||
FontId(raw_font as *const _)
|
||||
}
|
||||
pub fn fonts(&self) -> Vec<FontId> {
|
||||
let mut result = Vec::new();
|
||||
unsafe {
|
||||
for &font in self.fonts.as_slice() {
|
||||
result.push((*font).id());
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
pub fn get_font(&self, id: FontId) -> Option<&Font> {
|
||||
unsafe {
|
||||
for &font in self.fonts.as_slice() {
|
||||
if id == FontId(font) {
|
||||
return Some(&*(font as *const Font));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Returns true if the font atlas has been built
|
||||
#[doc(alias = "IsBuilt")]
|
||||
pub fn is_built(&self) -> bool {
|
||||
unsafe { sys::ImFontAtlas_IsBuilt(self.raw() as *const sys::ImFontAtlas as *mut _) }
|
||||
}
|
||||
/// Builds a 1 byte per-pixel font atlas texture
|
||||
#[doc(alias = "GetTextDataAsAlpha8")]
|
||||
pub fn build_alpha8_texture(&mut self) -> FontAtlasTexture<'_> {
|
||||
let mut pixels: *mut c_uchar = ptr::null_mut();
|
||||
let mut width: c_int = 0;
|
||||
let mut height: c_int = 0;
|
||||
let mut bytes_per_pixel: c_int = 0;
|
||||
unsafe {
|
||||
sys::ImFontAtlas_GetTexDataAsAlpha8(
|
||||
self.raw_mut(),
|
||||
&mut pixels,
|
||||
&mut width,
|
||||
&mut height,
|
||||
&mut bytes_per_pixel,
|
||||
);
|
||||
assert!(width >= 0, "font texture width must be positive");
|
||||
assert!(height >= 0, "font texture height must be positive");
|
||||
assert!(
|
||||
bytes_per_pixel >= 0,
|
||||
"font texture bytes per pixel must be positive"
|
||||
);
|
||||
let height = height as usize;
|
||||
// Check multiplication to avoid constructing an invalid slice in case of overflow
|
||||
let pitch = width
|
||||
.checked_mul(bytes_per_pixel)
|
||||
.expect("Overflow in font texture pitch calculation")
|
||||
as usize;
|
||||
FontAtlasTexture {
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
data: slice::from_raw_parts(pixels, pitch * height),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Builds a 4 byte per-pixel font atlas texture
|
||||
#[doc(alias = "GetTextDataAsRGBA32")]
|
||||
pub fn build_rgba32_texture(&mut self) -> FontAtlasTexture<'_> {
|
||||
let mut pixels: *mut c_uchar = ptr::null_mut();
|
||||
let mut width: c_int = 0;
|
||||
let mut height: c_int = 0;
|
||||
let mut bytes_per_pixel: c_int = 0;
|
||||
unsafe {
|
||||
sys::ImFontAtlas_GetTexDataAsRGBA32(
|
||||
self.raw_mut(),
|
||||
&mut pixels,
|
||||
&mut width,
|
||||
&mut height,
|
||||
&mut bytes_per_pixel,
|
||||
);
|
||||
assert!(width >= 0, "font texture width must be positive");
|
||||
assert!(height >= 0, "font texture height must be positive");
|
||||
assert!(
|
||||
bytes_per_pixel >= 0,
|
||||
"font texture bytes per pixel must be positive"
|
||||
);
|
||||
let height = height as usize;
|
||||
// Check multiplication to avoid constructing an invalid slice in case of overflow
|
||||
let pitch = width
|
||||
.checked_mul(bytes_per_pixel)
|
||||
.expect("Overflow in font texture pitch calculation")
|
||||
as usize;
|
||||
FontAtlasTexture {
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
data: slice::from_raw_parts(pixels, pitch * height),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Clears the font atlas completely (both input and output data)
|
||||
#[doc(alias = "Clear")]
|
||||
pub fn clear(&mut self) {
|
||||
unsafe {
|
||||
sys::ImFontAtlas_Clear(self.raw_mut());
|
||||
}
|
||||
}
|
||||
/// Clears output font data (glyph storage, UV coordinates)
|
||||
#[doc(alias = "ClearFonts")]
|
||||
pub fn clear_fonts(&mut self) {
|
||||
unsafe {
|
||||
sys::ImFontAtlas_ClearFonts(self.raw_mut());
|
||||
}
|
||||
}
|
||||
/// Clears output texture data.
|
||||
///
|
||||
/// Can be used to save RAM once the texture has been transferred to the GPU.
|
||||
#[doc(alias = "ClearTexData")]
|
||||
pub fn clear_tex_data(&mut self) {
|
||||
unsafe {
|
||||
sys::ImFontAtlas_ClearTexData(self.raw_mut());
|
||||
}
|
||||
}
|
||||
/// Clears all the data used to build the textures and fonts
|
||||
#[doc(alias = "ClearInputData")]
|
||||
pub fn clear_input_data(&mut self) {
|
||||
unsafe {
|
||||
sys::ImFontAtlas_ClearInputData(self.raw_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(test)]
|
||||
fn test_font_atlas_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(
|
||||
mem::size_of::<FontAtlas>(),
|
||||
mem::size_of::<sys::ImFontAtlas>()
|
||||
);
|
||||
assert_eq!(
|
||||
mem::align_of::<FontAtlas>(),
|
||||
mem::align_of::<sys::ImFontAtlas>()
|
||||
);
|
||||
use sys::ImFontAtlas;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(FontAtlas, $l),
|
||||
memoffset::offset_of!(ImFontAtlas, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(locked, Locked);
|
||||
assert_field_offset!(flags, Flags);
|
||||
assert_field_offset!(tex_id, TexID);
|
||||
assert_field_offset!(tex_desired_width, TexDesiredWidth);
|
||||
assert_field_offset!(tex_glyph_padding, TexGlyphPadding);
|
||||
assert_field_offset!(tex_pixels_use_colors, TexPixelsUseColors);
|
||||
assert_field_offset!(tex_pixels_alpha8, TexPixelsAlpha8);
|
||||
assert_field_offset!(tex_pixels_rgba32, TexPixelsRGBA32);
|
||||
assert_field_offset!(tex_width, TexWidth);
|
||||
assert_field_offset!(tex_height, TexHeight);
|
||||
assert_field_offset!(tex_uv_scale, TexUvScale);
|
||||
assert_field_offset!(tex_uv_white_pixel, TexUvWhitePixel);
|
||||
assert_field_offset!(fonts, Fonts);
|
||||
assert_field_offset!(custom_rects, CustomRects);
|
||||
assert_field_offset!(config_data, ConfigData);
|
||||
assert_field_offset!(tex_uv_lines, TexUvLines);
|
||||
assert_field_offset!(pack_id_mouse_cursors, PackIdMouseCursors);
|
||||
assert_field_offset!(pack_id_lines, PackIdLines);
|
||||
}
|
||||
|
||||
/// A source for binary font data
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum FontSource<'a> {
|
||||
/// Default font included with the library (ProggyClean.ttf)
|
||||
DefaultFontData { config: Option<FontConfig> },
|
||||
/// Binary TTF/OTF font data
|
||||
TtfData {
|
||||
data: &'a [u8],
|
||||
size_pixels: f32,
|
||||
config: Option<FontConfig>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Configuration settings for a font
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FontConfig {
|
||||
/// Size in pixels for the rasterizer
|
||||
pub size_pixels: f32,
|
||||
/// Horizontal oversampling
|
||||
pub oversample_h: i32,
|
||||
/// Vertical oversampling
|
||||
pub oversample_v: i32,
|
||||
/// Align every glyph to pixel boundary
|
||||
pub pixel_snap_h: bool,
|
||||
/// Extra spacing (in pixels) between glyphs
|
||||
pub glyph_extra_spacing: [f32; 2],
|
||||
/// Offset for all glyphs in this font
|
||||
pub glyph_offset: [f32; 2],
|
||||
/// Unicode ranges to use from this font
|
||||
pub glyph_ranges: FontGlyphRanges,
|
||||
/// Minimum advance_x for glyphs
|
||||
pub glyph_min_advance_x: f32,
|
||||
/// Maximum advance_x for glyphs
|
||||
pub glyph_max_advance_x: f32,
|
||||
/// Settings for a custom font rasterizer if used
|
||||
pub font_builder_flags: u32,
|
||||
/// Brighten (>1.0) or darken (<1.0) font output
|
||||
pub rasterizer_multiply: f32,
|
||||
/// Explicitly specify the ellipsis character.
|
||||
///
|
||||
/// With multiple font sources the first specified ellipsis is used.
|
||||
pub ellipsis_char: Option<char>,
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for FontConfig {
|
||||
fn default() -> FontConfig {
|
||||
FontConfig {
|
||||
size_pixels: 0.0,
|
||||
oversample_h: 3,
|
||||
oversample_v: 1,
|
||||
pixel_snap_h: false,
|
||||
glyph_extra_spacing: [0.0, 0.0],
|
||||
glyph_offset: [0.0, 0.0],
|
||||
glyph_ranges: FontGlyphRanges::default(),
|
||||
glyph_min_advance_x: 0.0,
|
||||
glyph_max_advance_x: f32::MAX,
|
||||
font_builder_flags: 0,
|
||||
rasterizer_multiply: 1.0,
|
||||
ellipsis_char: None,
|
||||
name: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FontConfig {
|
||||
fn apply_to_raw_config(&self, raw: &mut sys::ImFontConfig, atlas: *mut sys::ImFontAtlas) {
|
||||
raw.SizePixels = self.size_pixels;
|
||||
raw.OversampleH = self.oversample_h;
|
||||
raw.OversampleV = self.oversample_v;
|
||||
raw.PixelSnapH = self.pixel_snap_h;
|
||||
raw.GlyphExtraSpacing = self.glyph_extra_spacing.into();
|
||||
raw.GlyphOffset = self.glyph_offset.into();
|
||||
raw.GlyphRanges = unsafe { self.glyph_ranges.to_ptr(atlas) };
|
||||
raw.GlyphMinAdvanceX = self.glyph_min_advance_x;
|
||||
raw.GlyphMaxAdvanceX = self.glyph_max_advance_x;
|
||||
raw.FontBuilderFlags = self.font_builder_flags;
|
||||
raw.RasterizerMultiply = self.rasterizer_multiply;
|
||||
// char is used as "unset" for EllipsisChar
|
||||
raw.EllipsisChar = self.ellipsis_char.map(|c| c as u32).unwrap_or(!0);
|
||||
if let Some(name) = self.name.as_ref() {
|
||||
let bytes = name.as_bytes();
|
||||
let mut len = bytes.len().min(raw.Name.len() - 1);
|
||||
while !name.is_char_boundary(len) {
|
||||
len -= 1;
|
||||
}
|
||||
unsafe {
|
||||
bytes.as_ptr().copy_to(raw.Name.as_mut_ptr() as _, len);
|
||||
raw.Name[len] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sys_font_config_default() -> sys::ImFontConfig {
|
||||
unsafe {
|
||||
let heap_allocated = sys::ImFontConfig_ImFontConfig();
|
||||
let copy = *heap_allocated;
|
||||
sys::ImFontConfig_destroy(heap_allocated);
|
||||
copy
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_font_config_default() {
|
||||
let sys_font_config = sys_font_config_default();
|
||||
let font_config = FontConfig::default();
|
||||
assert_eq!(font_config.size_pixels, sys_font_config.SizePixels);
|
||||
assert_eq!(font_config.oversample_h, sys_font_config.OversampleH);
|
||||
assert_eq!(font_config.oversample_v, sys_font_config.OversampleV);
|
||||
assert_eq!(font_config.pixel_snap_h, sys_font_config.PixelSnapH);
|
||||
assert_eq!(
|
||||
font_config.glyph_extra_spacing[0],
|
||||
sys_font_config.GlyphExtraSpacing.x
|
||||
);
|
||||
assert_eq!(
|
||||
font_config.glyph_extra_spacing[1],
|
||||
sys_font_config.GlyphExtraSpacing.y
|
||||
);
|
||||
assert_eq!(font_config.glyph_offset[0], sys_font_config.GlyphOffset.x);
|
||||
assert_eq!(font_config.glyph_offset[1], sys_font_config.GlyphOffset.y);
|
||||
assert_eq!(
|
||||
font_config.glyph_min_advance_x,
|
||||
sys_font_config.GlyphMinAdvanceX
|
||||
);
|
||||
assert_eq!(
|
||||
font_config.glyph_max_advance_x,
|
||||
sys_font_config.GlyphMaxAdvanceX
|
||||
);
|
||||
assert_eq!(
|
||||
font_config.font_builder_flags,
|
||||
sys_font_config.FontBuilderFlags
|
||||
);
|
||||
assert_eq!(
|
||||
font_config.rasterizer_multiply,
|
||||
sys_font_config.RasterizerMultiply
|
||||
);
|
||||
}
|
||||
|
||||
/// Handle to a font atlas texture
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FontAtlasTexture<'a> {
|
||||
/// Texture width (in pixels)
|
||||
pub width: u32,
|
||||
/// Texture height (in pixels)
|
||||
pub height: u32,
|
||||
/// Raw texture data (in bytes).
|
||||
///
|
||||
/// The format depends on which function was called to obtain this data.
|
||||
pub data: &'a [u8],
|
||||
}
|
||||
|
||||
/// A font atlas that can be shared between contexts
|
||||
#[derive(Debug)]
|
||||
pub struct SharedFontAtlas(pub(crate) *mut sys::ImFontAtlas);
|
||||
|
||||
impl SharedFontAtlas {
|
||||
#[doc(alias = "ImFontAtlas", alias = "ImFontAtlas::ImFontAtlas")]
|
||||
pub fn create() -> SharedFontAtlas {
|
||||
SharedFontAtlas(unsafe { sys::ImFontAtlas_ImFontAtlas() })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SharedFontAtlas {
|
||||
#[doc(alias = "ImFontAtlas::Destory")]
|
||||
fn drop(&mut self) {
|
||||
unsafe { sys::ImFontAtlas_destroy(self.0) };
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for SharedFontAtlas {
|
||||
type Target = FontAtlas;
|
||||
fn deref(&self) -> &FontAtlas {
|
||||
unsafe { &*(self.0 as *const FontAtlas) }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for SharedFontAtlas {
|
||||
fn deref_mut(&mut self) -> &mut FontAtlas {
|
||||
unsafe { &mut *(self.0 as *mut FontAtlas) }
|
||||
}
|
||||
}
|
||||
|
||||
/// An immutably borrowed reference to a (possibly shared) font atlas
|
||||
pub enum FontAtlasRef<'a> {
|
||||
Owned(&'a FontAtlas),
|
||||
Shared(&'a cell::RefMut<'a, SharedFontAtlas>),
|
||||
}
|
||||
|
||||
impl<'a> Deref for FontAtlasRef<'a> {
|
||||
type Target = FontAtlas;
|
||||
fn deref(&self) -> &FontAtlas {
|
||||
use self::FontAtlasRef::*;
|
||||
match self {
|
||||
Owned(atlas) => atlas,
|
||||
Shared(cell) => cell,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A mutably borrowed reference to a (possibly shared) font atlas
|
||||
pub enum FontAtlasRefMut<'a> {
|
||||
Owned(&'a mut FontAtlas),
|
||||
Shared(cell::RefMut<'a, SharedFontAtlas>),
|
||||
}
|
||||
|
||||
impl<'a> Deref for FontAtlasRefMut<'a> {
|
||||
type Target = FontAtlas;
|
||||
fn deref(&self) -> &FontAtlas {
|
||||
use self::FontAtlasRefMut::*;
|
||||
match self {
|
||||
Owned(atlas) => atlas,
|
||||
Shared(cell) => cell,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for FontAtlasRefMut<'a> {
|
||||
fn deref_mut(&mut self) -> &mut FontAtlas {
|
||||
use self::FontAtlasRefMut::*;
|
||||
match self {
|
||||
Owned(atlas) => atlas,
|
||||
Shared(cell) => cell,
|
||||
}
|
||||
}
|
||||
}
|
||||
71
plugins/libimhex-rust/imgui-rs/src/fonts/font.rs
vendored
Normal file
71
plugins/libimhex-rust/imgui-rs/src/fonts/font.rs
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use crate::fonts::atlas::{FontAtlas, FontId};
|
||||
use crate::fonts::glyph::FontGlyph;
|
||||
use crate::internal::{ImVector, RawCast};
|
||||
use crate::sys;
|
||||
|
||||
/// Runtime data for a single font within a font atlas
|
||||
#[repr(C)]
|
||||
pub struct Font {
|
||||
index_advance_x: ImVector<f32>,
|
||||
pub fallback_advance_x: f32,
|
||||
pub font_size: f32,
|
||||
index_lookup: ImVector<sys::ImWchar>,
|
||||
glyphs: ImVector<FontGlyph>,
|
||||
fallback_glyph: *const FontGlyph,
|
||||
container_atlas: *mut FontAtlas,
|
||||
config_data: *const sys::ImFontConfig,
|
||||
pub config_data_count: i16,
|
||||
pub fallback_char: sys::ImWchar,
|
||||
pub ellipsis_char: sys::ImWchar,
|
||||
pub dot_char: sys::ImWchar,
|
||||
pub dirty_lookup_tables: bool,
|
||||
pub scale: f32,
|
||||
pub ascent: f32,
|
||||
pub descent: f32,
|
||||
pub metrics_total_surface: c_int,
|
||||
pub used_4k_pages_map: [u8; 34],
|
||||
}
|
||||
|
||||
unsafe impl RawCast<sys::ImFont> for Font {}
|
||||
|
||||
impl Font {
|
||||
/// Returns the identifier of this font
|
||||
pub fn id(&self) -> FontId {
|
||||
FontId(self as *const _)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_font_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(mem::size_of::<Font>(), mem::size_of::<sys::ImFont>());
|
||||
assert_eq!(mem::align_of::<Font>(), mem::align_of::<sys::ImFont>());
|
||||
use sys::ImFont;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(Font, $l),
|
||||
memoffset::offset_of!(ImFont, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(index_advance_x, IndexAdvanceX);
|
||||
assert_field_offset!(fallback_advance_x, FallbackAdvanceX);
|
||||
assert_field_offset!(font_size, FontSize);
|
||||
assert_field_offset!(index_lookup, IndexLookup);
|
||||
assert_field_offset!(glyphs, Glyphs);
|
||||
assert_field_offset!(fallback_glyph, FallbackGlyph);
|
||||
assert_field_offset!(container_atlas, ContainerAtlas);
|
||||
assert_field_offset!(config_data, ConfigData);
|
||||
assert_field_offset!(config_data_count, ConfigDataCount);
|
||||
assert_field_offset!(fallback_char, FallbackChar);
|
||||
assert_field_offset!(ellipsis_char, EllipsisChar);
|
||||
assert_field_offset!(dirty_lookup_tables, DirtyLookupTables);
|
||||
assert_field_offset!(scale, Scale);
|
||||
assert_field_offset!(ascent, Ascent);
|
||||
assert_field_offset!(descent, Descent);
|
||||
assert_field_offset!(metrics_total_surface, MetricsTotalSurface);
|
||||
assert_field_offset!(used_4k_pages_map, Used4kPagesMap);
|
||||
}
|
||||
67
plugins/libimhex-rust/imgui-rs/src/fonts/glyph.rs
vendored
Normal file
67
plugins/libimhex-rust/imgui-rs/src/fonts/glyph.rs
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
use crate::internal::RawCast;
|
||||
use crate::sys;
|
||||
|
||||
/// A single font glyph
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct FontGlyph {
|
||||
bitfields: u32,
|
||||
pub advance_x: f32,
|
||||
pub x0: f32,
|
||||
pub y0: f32,
|
||||
pub x1: f32,
|
||||
pub y1: f32,
|
||||
pub u0: f32,
|
||||
pub v0: f32,
|
||||
pub u1: f32,
|
||||
pub v1: f32,
|
||||
}
|
||||
|
||||
impl FontGlyph {
|
||||
pub fn codepoint(&self) -> u32 {
|
||||
unsafe { self.raw().Codepoint() }
|
||||
}
|
||||
pub fn set_codepoint(&mut self, codepoint: u32) {
|
||||
unsafe { self.raw_mut().set_Codepoint(codepoint) };
|
||||
}
|
||||
pub fn visible(&self) -> bool {
|
||||
unsafe { self.raw().Visible() != 0 }
|
||||
}
|
||||
pub fn set_visible(&mut self, visible: bool) {
|
||||
unsafe { self.raw_mut().set_Visible(visible as u32) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl RawCast<sys::ImFontGlyph> for FontGlyph {}
|
||||
|
||||
#[test]
|
||||
fn test_font_glyph_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(
|
||||
mem::size_of::<FontGlyph>(),
|
||||
mem::size_of::<sys::ImFontGlyph>()
|
||||
);
|
||||
assert_eq!(
|
||||
mem::align_of::<FontGlyph>(),
|
||||
mem::align_of::<sys::ImFontGlyph>()
|
||||
);
|
||||
use sys::ImFontGlyph;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(FontGlyph, $l),
|
||||
memoffset::offset_of!(ImFontGlyph, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(bitfields, _bitfield_1);
|
||||
assert_field_offset!(advance_x, AdvanceX);
|
||||
assert_field_offset!(x0, X0);
|
||||
assert_field_offset!(y0, Y0);
|
||||
assert_field_offset!(x1, X1);
|
||||
assert_field_offset!(y1, Y1);
|
||||
assert_field_offset!(u0, U0);
|
||||
assert_field_offset!(v0, V0);
|
||||
assert_field_offset!(u1, U1);
|
||||
assert_field_offset!(v1, V1);
|
||||
}
|
||||
164
plugins/libimhex-rust/imgui-rs/src/fonts/glyph_ranges.rs
vendored
Normal file
164
plugins/libimhex-rust/imgui-rs/src/fonts/glyph_ranges.rs
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
use crate::sys;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
enum FontGlyphRangeData {
|
||||
ChineseSimplifiedCommon,
|
||||
ChineseFull,
|
||||
Cyrillic,
|
||||
Default,
|
||||
Japanese,
|
||||
Korean,
|
||||
Thai,
|
||||
Vietnamese,
|
||||
Custom(*const sys::ImWchar),
|
||||
}
|
||||
|
||||
/// A set of Unicode codepoints
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct FontGlyphRanges(FontGlyphRangeData);
|
||||
impl FontGlyphRanges {
|
||||
/// The default set of glyph ranges used by imgui.
|
||||
pub fn default() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Default)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with simplified common Chinese text.
|
||||
pub fn chinese_simplified_common() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::ChineseSimplifiedCommon)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Chinese text.
|
||||
pub fn chinese_full() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::ChineseFull)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Cyrillic text.
|
||||
pub fn cyrillic() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Cyrillic)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Japanese text.
|
||||
pub fn japanese() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Japanese)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Korean text.
|
||||
pub fn korean() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Korean)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Thai text.
|
||||
pub fn thai() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Thai)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Vietnamese text.
|
||||
pub fn vietnamese() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Vietnamese)
|
||||
}
|
||||
|
||||
/// Creates a glyph range from a static slice. The expected format is a series of pairs of
|
||||
/// non-zero codepoints, each representing an inclusive range, followed by a single
|
||||
/// zero terminating the range. The ranges must not overlap.
|
||||
///
|
||||
/// As the slice is expected to last as long as a font is used, and is written into global
|
||||
/// state, it must be `'static`.
|
||||
///
|
||||
/// Panics
|
||||
/// ======
|
||||
///
|
||||
/// This function will panic if the given slice is not a valid font range.
|
||||
// TODO(thom): This takes `u32` for now, since I believe it's fine for it to
|
||||
// contain surrogates? (It seems plausible that font data can describe what
|
||||
// to show for unpaired surrogates) Would be nice to be sure, if so, this
|
||||
// should accept `char` (we'd still have to check that the range doesn't
|
||||
// fully contain the surrogate range though)
|
||||
pub fn from_slice(slice: &'static [u32]) -> FontGlyphRanges {
|
||||
assert_eq!(
|
||||
slice.len() % 2,
|
||||
1,
|
||||
"The length of a glyph range must be odd."
|
||||
);
|
||||
assert_eq!(
|
||||
slice.last(),
|
||||
Some(&0),
|
||||
"A glyph range must be zero-terminated."
|
||||
);
|
||||
|
||||
for (i, &glyph) in slice.iter().enumerate().take(slice.len() - 1) {
|
||||
assert_ne!(
|
||||
glyph, 0,
|
||||
"A glyph in a range cannot be zero. \
|
||||
(Glyph is zero at index {})",
|
||||
i
|
||||
);
|
||||
assert!(
|
||||
glyph <= core::char::MAX as u32,
|
||||
"A glyph in a range cannot exceed the maximum codepoint. \
|
||||
(Glyph is {:#x} at index {})",
|
||||
glyph,
|
||||
i,
|
||||
);
|
||||
}
|
||||
|
||||
let mut ranges = Vec::new();
|
||||
for i in 0..slice.len() / 2 {
|
||||
let (start, end) = (slice[i * 2], slice[i * 2 + 1]);
|
||||
assert!(
|
||||
start <= end,
|
||||
"The start of a range cannot be larger than its end. \
|
||||
(At index {}, {} > {})",
|
||||
i * 2,
|
||||
start,
|
||||
end
|
||||
);
|
||||
ranges.push((start, end));
|
||||
}
|
||||
ranges.sort_unstable_by_key(|x| x.0);
|
||||
for i in 0..ranges.len() - 1 {
|
||||
let (range_a, range_b) = (ranges[i], ranges[i + 1]);
|
||||
if range_a.1 >= range_b.0 {
|
||||
panic!(
|
||||
"The glyph ranges {:?} and {:?} overlap between {:?}.",
|
||||
range_a,
|
||||
range_b,
|
||||
(range_a.1, range_b.0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { FontGlyphRanges::from_slice_unchecked(slice) }
|
||||
}
|
||||
|
||||
/// Creates a glyph range from a static slice without checking its validity.
|
||||
///
|
||||
/// See [`FontGlyphRanges::from_slice`] for more information.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the slice contents are valid.
|
||||
pub unsafe fn from_slice_unchecked(slice: &'static [u32]) -> FontGlyphRanges {
|
||||
FontGlyphRanges::from_ptr(slice.as_ptr())
|
||||
}
|
||||
|
||||
/// Creates a glyph range from a pointer, without checking its validity or enforcing its
|
||||
/// lifetime. The memory the pointer points to must be valid for as long as the font is
|
||||
/// in use.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the pointer is not null, remains valid forever, and
|
||||
/// points to valid data.
|
||||
pub unsafe fn from_ptr(ptr: *const u32) -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Custom(ptr))
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn to_ptr(&self, atlas: *mut sys::ImFontAtlas) -> *const sys::ImWchar {
|
||||
match self.0 {
|
||||
FontGlyphRangeData::ChineseFull => sys::ImFontAtlas_GetGlyphRangesChineseFull(atlas),
|
||||
FontGlyphRangeData::ChineseSimplifiedCommon => {
|
||||
sys::ImFontAtlas_GetGlyphRangesChineseSimplifiedCommon(atlas)
|
||||
}
|
||||
FontGlyphRangeData::Cyrillic => sys::ImFontAtlas_GetGlyphRangesCyrillic(atlas),
|
||||
FontGlyphRangeData::Default => sys::ImFontAtlas_GetGlyphRangesDefault(atlas),
|
||||
FontGlyphRangeData::Japanese => sys::ImFontAtlas_GetGlyphRangesJapanese(atlas),
|
||||
FontGlyphRangeData::Korean => sys::ImFontAtlas_GetGlyphRangesKorean(atlas),
|
||||
FontGlyphRangeData::Thai => sys::ImFontAtlas_GetGlyphRangesThai(atlas),
|
||||
FontGlyphRangeData::Vietnamese => sys::ImFontAtlas_GetGlyphRangesVietnamese(atlas),
|
||||
FontGlyphRangeData::Custom(ptr) => ptr,
|
||||
}
|
||||
}
|
||||
}
|
||||
36
plugins/libimhex-rust/imgui-rs/src/fonts/mod.rs
vendored
Normal file
36
plugins/libimhex-rust/imgui-rs/src/fonts/mod.rs
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
use crate::fonts::font::Font;
|
||||
use crate::internal::RawCast;
|
||||
use crate::Ui;
|
||||
|
||||
pub mod atlas;
|
||||
pub mod font;
|
||||
pub mod glyph;
|
||||
pub mod glyph_ranges;
|
||||
|
||||
/// # Fonts
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Returns the current font
|
||||
#[doc(alias = "GetFont")]
|
||||
pub fn current_font(&self) -> &Font {
|
||||
unsafe { Font::from_raw(&*sys::igGetFont()) }
|
||||
}
|
||||
/// Returns the current font size (= height in pixels) with font scale applied
|
||||
#[doc(alias = "GetFontSize")]
|
||||
pub fn current_font_size(&self) -> f32 {
|
||||
unsafe { sys::igGetFontSize() }
|
||||
}
|
||||
/// Returns the UV coordinate for a white pixel.
|
||||
///
|
||||
/// Useful for drawing custom shapes with the draw list API.
|
||||
#[doc(alias = "FontTexUvWhitePixel")]
|
||||
pub fn font_tex_uv_white_pixel(&self) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetFontTexUvWhitePixel(&mut out) };
|
||||
out.into()
|
||||
}
|
||||
/// Sets the font scale of the current window
|
||||
#[doc(alias = "SetWindowFontScale")]
|
||||
pub fn set_window_font_scale(&self, scale: f32) {
|
||||
unsafe { sys::igSetWindowFontScale(scale) }
|
||||
}
|
||||
}
|
||||
215
plugins/libimhex-rust/imgui-rs/src/input/keyboard.rs
vendored
Normal file
215
plugins/libimhex-rust/imgui-rs/src/input/keyboard.rs
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
/// A key identifier
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum Key {
|
||||
Tab = sys::ImGuiKey_Tab,
|
||||
LeftArrow = sys::ImGuiKey_LeftArrow,
|
||||
RightArrow = sys::ImGuiKey_RightArrow,
|
||||
UpArrow = sys::ImGuiKey_UpArrow,
|
||||
DownArrow = sys::ImGuiKey_DownArrow,
|
||||
PageUp = sys::ImGuiKey_PageUp,
|
||||
PageDown = sys::ImGuiKey_PageDown,
|
||||
Home = sys::ImGuiKey_Home,
|
||||
End = sys::ImGuiKey_End,
|
||||
Insert = sys::ImGuiKey_Insert,
|
||||
Delete = sys::ImGuiKey_Delete,
|
||||
Backspace = sys::ImGuiKey_Backspace,
|
||||
Space = sys::ImGuiKey_Space,
|
||||
Enter = sys::ImGuiKey_Enter,
|
||||
Escape = sys::ImGuiKey_Escape,
|
||||
KeyPadEnter = sys::ImGuiKey_KeyPadEnter,
|
||||
A = sys::ImGuiKey_A,
|
||||
C = sys::ImGuiKey_C,
|
||||
V = sys::ImGuiKey_V,
|
||||
X = sys::ImGuiKey_X,
|
||||
Y = sys::ImGuiKey_Y,
|
||||
Z = sys::ImGuiKey_Z,
|
||||
}
|
||||
|
||||
impl Key {
|
||||
/// All possible `Key` variants
|
||||
pub const VARIANTS: [Key; Key::COUNT] = [
|
||||
Key::Tab,
|
||||
Key::LeftArrow,
|
||||
Key::RightArrow,
|
||||
Key::UpArrow,
|
||||
Key::DownArrow,
|
||||
Key::PageUp,
|
||||
Key::PageDown,
|
||||
Key::Home,
|
||||
Key::End,
|
||||
Key::Insert,
|
||||
Key::Delete,
|
||||
Key::Backspace,
|
||||
Key::Space,
|
||||
Key::Enter,
|
||||
Key::Escape,
|
||||
Key::KeyPadEnter,
|
||||
Key::A,
|
||||
Key::C,
|
||||
Key::V,
|
||||
Key::X,
|
||||
Key::Y,
|
||||
Key::Z,
|
||||
];
|
||||
/// Total count of `Key` variants
|
||||
pub const COUNT: usize = sys::ImGuiKey_COUNT as usize;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_key_variants() {
|
||||
for (idx, &value) in Key::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
|
||||
/// Target widget selection for keyboard focus
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum FocusedWidget {
|
||||
/// Previous widget
|
||||
Previous,
|
||||
/// Next widget
|
||||
Next,
|
||||
/// Widget using a relative positive offset (0 is the next widget).
|
||||
///
|
||||
/// Use this to access sub components of a multiple component widget.
|
||||
Offset(u32),
|
||||
}
|
||||
|
||||
impl FocusedWidget {
|
||||
#[inline]
|
||||
fn as_offset(self) -> i32 {
|
||||
match self {
|
||||
FocusedWidget::Previous => -1,
|
||||
FocusedWidget::Next => 0,
|
||||
FocusedWidget::Offset(offset) => offset as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # Input: Keyboard
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Returns the key index of the given key identifier.
|
||||
///
|
||||
/// Equivalent to indexing the Io struct `key_map` field: `ui.io().key_map[key]`
|
||||
#[inline]
|
||||
#[doc(alias = "GetKeyIndex")]
|
||||
fn key_index(&self, key: Key) -> i32 {
|
||||
unsafe { sys::igGetKeyIndex(key as i32) }
|
||||
}
|
||||
/// Returns true if the key is being held.
|
||||
///
|
||||
/// Equivalent to indexing the Io struct `keys_down` field: `ui.io().keys_down[key_index]`
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyDown")]
|
||||
pub fn is_key_down(&self, key: Key) -> bool {
|
||||
let key_index = self.key_index(key);
|
||||
self.is_key_index_down(key_index)
|
||||
}
|
||||
|
||||
/// Same as [`is_key_down`](Self::is_key_down) but takes a key index. The meaning of
|
||||
/// index is defined by your backend implementation.
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyDown")]
|
||||
pub fn is_key_index_down(&self, key_index: i32) -> bool {
|
||||
unsafe { sys::igIsKeyDown(key_index) }
|
||||
}
|
||||
|
||||
/// Returns true if the key was pressed (went from !down to down).
|
||||
///
|
||||
/// Affected by key repeat settings (`io.key_repeat_delay`, `io.key_repeat_rate`)
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyPressed")]
|
||||
pub fn is_key_pressed(&self, key: Key) -> bool {
|
||||
let key_index = self.key_index(key);
|
||||
self.is_key_index_pressed(key_index)
|
||||
}
|
||||
|
||||
/// Same as [`is_key_pressed`](Self::is_key_pressed) but takes a key index.
|
||||
///
|
||||
/// The meaning of index is defined by your backend
|
||||
/// implementation.
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyPressed")]
|
||||
pub fn is_key_index_pressed(&self, key_index: i32) -> bool {
|
||||
unsafe { sys::igIsKeyPressed(key_index, true) }
|
||||
}
|
||||
|
||||
/// Returns true if the key was pressed (went from !down to down).
|
||||
///
|
||||
/// Is **not** affected by key repeat settings (`io.key_repeat_delay`, `io.key_repeat_rate`)
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyPressed")]
|
||||
pub fn is_key_pressed_no_repeat(&self, key: Key) -> bool {
|
||||
let key_index = self.key_index(key);
|
||||
self.is_key_index_pressed_no_repeat(key_index)
|
||||
}
|
||||
|
||||
/// Same as [`is_key_pressed_no_repeat`](Self::is_key_pressed_no_repeat)
|
||||
/// but takes a key index.
|
||||
///
|
||||
/// The meaning of index is defined by your backend
|
||||
/// implementation.
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyPressed")]
|
||||
pub fn is_key_index_pressed_no_repeat(&self, key_index: i32) -> bool {
|
||||
unsafe { sys::igIsKeyPressed(key_index, false) }
|
||||
}
|
||||
|
||||
/// Returns true if the key was released (went from down to !down)
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyReleased")]
|
||||
pub fn is_key_released(&self, key: Key) -> bool {
|
||||
let key_index = self.key_index(key);
|
||||
self.is_key_index_released(key_index)
|
||||
}
|
||||
|
||||
/// Same as [`is_key_released`](Self::is_key_released) but takes a key index.
|
||||
///
|
||||
/// The meaning of index is defined by your backend
|
||||
/// implementation.
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyReleased")]
|
||||
pub fn is_key_index_released(&self, key_index: i32) -> bool {
|
||||
unsafe { sys::igIsKeyReleased(key_index) }
|
||||
}
|
||||
|
||||
/// Returns a count of key presses using the given repeat rate/delay settings.
|
||||
///
|
||||
/// Usually returns 0 or 1, but might be >1 if `rate` is small enough that `io.delta_time` >
|
||||
/// `rate`.
|
||||
#[inline]
|
||||
#[doc(alias = "GetKeyPressedAmount")]
|
||||
pub fn key_pressed_amount(&self, key: Key, repeat_delay: f32, rate: f32) -> u32 {
|
||||
let key_index = self.key_index(key);
|
||||
self.key_index_pressed_amount(key_index, repeat_delay, rate)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[doc(alias = "GetKeyPressedAmount")]
|
||||
pub fn key_index_pressed_amount(&self, key_index: i32, repeat_delay: f32, rate: f32) -> u32 {
|
||||
unsafe { sys::igGetKeyPressedAmount(key_index, repeat_delay, rate) as u32 }
|
||||
}
|
||||
|
||||
/// Focuses keyboard on the next widget.
|
||||
///
|
||||
/// This is the equivalent to [set_keyboard_focus_here_with_offset](Self::set_keyboard_focus_here_with_offset)
|
||||
/// with `target_widget` set to `FocusedWidget::Next`.
|
||||
#[inline]
|
||||
#[doc(alias = "SetKeyboardFocusHere")]
|
||||
pub fn set_keyboard_focus_here(&self) {
|
||||
self.set_keyboard_focus_here_with_offset(FocusedWidget::Next);
|
||||
}
|
||||
|
||||
/// Focuses keyboard on a widget relative to current position.
|
||||
#[inline]
|
||||
#[doc(alias = "SetKeyboardFocusHere")]
|
||||
pub fn set_keyboard_focus_here_with_offset(&self, target_widget: FocusedWidget) {
|
||||
unsafe {
|
||||
sys::igSetKeyboardFocusHere(target_widget.as_offset());
|
||||
}
|
||||
}
|
||||
}
|
||||
2
plugins/libimhex-rust/imgui-rs/src/input/mod.rs
vendored
Normal file
2
plugins/libimhex-rust/imgui-rs/src/input/mod.rs
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod keyboard;
|
||||
pub mod mouse;
|
||||
478
plugins/libimhex-rust/imgui-rs/src/input/mouse.rs
vendored
Normal file
478
plugins/libimhex-rust/imgui-rs/src/input/mouse.rs
vendored
Normal file
@@ -0,0 +1,478 @@
|
||||
use std::ptr;
|
||||
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
/// Represents one of the supported mouse buttons
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum MouseButton {
|
||||
Left = 0,
|
||||
Right = 1,
|
||||
Middle = 2,
|
||||
Extra1 = 3,
|
||||
Extra2 = 4,
|
||||
}
|
||||
|
||||
impl MouseButton {
|
||||
/// All possible `MouseButton` varirants
|
||||
pub const VARIANTS: [MouseButton; MouseButton::COUNT] = [
|
||||
MouseButton::Left,
|
||||
MouseButton::Right,
|
||||
MouseButton::Middle,
|
||||
MouseButton::Extra1,
|
||||
MouseButton::Extra2,
|
||||
];
|
||||
/// Total count of `MouseButton` variants
|
||||
pub const COUNT: usize = 5;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_button_variants() {
|
||||
for (idx, &value) in MouseButton::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
|
||||
/// Mouse cursor type identifier
|
||||
#[repr(i32)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
// TODO: this should just be `#[allow(clippy::upper_case_acronyms)]`, but doing
|
||||
// so in a way that works before it stabilizes is a pain (in part because
|
||||
// `unknown_clippy_lints` was renamed to unknown_lints). Oh well, it's over a
|
||||
// small amount of code.
|
||||
#[allow(warnings)]
|
||||
pub enum MouseCursor {
|
||||
Arrow = sys::ImGuiMouseCursor_Arrow,
|
||||
/// Automatically used when hovering over text inputs, etc.
|
||||
TextInput = sys::ImGuiMouseCursor_TextInput,
|
||||
/// Not used automatically
|
||||
ResizeAll = sys::ImGuiMouseCursor_ResizeAll,
|
||||
/// Automatically used when hovering over a horizontal border
|
||||
ResizeNS = sys::ImGuiMouseCursor_ResizeNS,
|
||||
/// Automatically used when hovering over a vertical border or a column
|
||||
ResizeEW = sys::ImGuiMouseCursor_ResizeEW,
|
||||
/// Automatically used when hovering over the bottom-left corner of a window
|
||||
ResizeNESW = sys::ImGuiMouseCursor_ResizeNESW,
|
||||
/// Automatically used when hovering over the bottom-right corner of a window
|
||||
ResizeNWSE = sys::ImGuiMouseCursor_ResizeNWSE,
|
||||
/// Not used automatically, use for e.g. hyperlinks
|
||||
Hand = sys::ImGuiMouseCursor_Hand,
|
||||
/// When hovering something with disallowed interactions.
|
||||
///
|
||||
/// Usually a crossed circle.
|
||||
NotAllowed = sys::ImGuiMouseCursor_NotAllowed,
|
||||
}
|
||||
|
||||
impl MouseCursor {
|
||||
/// All possible `MouseCursor` varirants
|
||||
pub const VARIANTS: [MouseCursor; MouseCursor::COUNT] = [
|
||||
MouseCursor::Arrow,
|
||||
MouseCursor::TextInput,
|
||||
MouseCursor::ResizeAll,
|
||||
MouseCursor::ResizeNS,
|
||||
MouseCursor::ResizeEW,
|
||||
MouseCursor::ResizeNESW,
|
||||
MouseCursor::ResizeNWSE,
|
||||
MouseCursor::Hand,
|
||||
MouseCursor::NotAllowed,
|
||||
];
|
||||
/// Total count of `MouseCursor` variants
|
||||
pub const COUNT: usize = sys::ImGuiMouseCursor_COUNT as usize;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_cursor_variants() {
|
||||
for (idx, &value) in MouseCursor::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
|
||||
/// # Input: Mouse
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Returns true if the given mouse button is held down.
|
||||
///
|
||||
/// Equivalent to indexing the Io struct with the button, e.g. `ui.io()[button]`.
|
||||
#[doc(alias = "IsMouseDown")]
|
||||
pub fn is_mouse_down(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDown(button as i32) }
|
||||
}
|
||||
/// Returns true if any mouse button is held down
|
||||
#[doc(alias = "IsAnyMouseDown")]
|
||||
pub fn is_any_mouse_down(&self) -> bool {
|
||||
unsafe { sys::igIsAnyMouseDown() }
|
||||
}
|
||||
/// Returns true if the given mouse button was clicked (went from !down to down)
|
||||
#[doc(alias = "IsMouseClicked")]
|
||||
pub fn is_mouse_clicked(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseClicked(button as i32, false) }
|
||||
}
|
||||
/// Returns true if the given mouse button was double-clicked
|
||||
#[doc(alias = "IsMouseDoubleClicked")]
|
||||
pub fn is_mouse_double_clicked(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDoubleClicked(button as i32) }
|
||||
}
|
||||
/// Returns true if the given mouse button was released (went from down to !down)
|
||||
#[doc(alias = "IsMouseReleased")]
|
||||
pub fn is_mouse_released(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseReleased(button as i32) }
|
||||
}
|
||||
/// Returns true if the mouse is currently dragging with the given mouse button held down
|
||||
#[doc(alias = "IsMouseDragging")]
|
||||
pub fn is_mouse_dragging(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDragging(button as i32, -1.0) }
|
||||
}
|
||||
/// Returns true if the mouse is currently dragging with the given mouse button held down.
|
||||
///
|
||||
/// If the given threshold is invalid or negative, the global distance threshold is used
|
||||
/// (`io.mouse_drag_threshold`).
|
||||
#[doc(alias = "IsMouseDragging")]
|
||||
pub fn is_mouse_dragging_with_threshold(&self, button: MouseButton, threshold: f32) -> bool {
|
||||
unsafe { sys::igIsMouseDragging(button as i32, threshold) }
|
||||
}
|
||||
/// Returns true if the mouse is hovering over the given bounding rect.
|
||||
///
|
||||
/// Clipped by current clipping settings, but disregards other factors like focus, window
|
||||
/// ordering, modal popup blocking.
|
||||
pub fn is_mouse_hovering_rect(&self, r_min: [f32; 2], r_max: [f32; 2]) -> bool {
|
||||
unsafe { sys::igIsMouseHoveringRect(r_min.into(), r_max.into(), true) }
|
||||
}
|
||||
/// Returns the mouse position backed up at the time of opening a popup
|
||||
#[doc(alias = "GetMousePosOnOpeningCurrentPopup")]
|
||||
pub fn mouse_pos_on_opening_current_popup(&self) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetMousePosOnOpeningCurrentPopup(&mut out) };
|
||||
out.into()
|
||||
}
|
||||
|
||||
/// Returns the delta from the initial position when the left mouse button clicked.
|
||||
///
|
||||
/// This is locked and returns [0.0, 0.0] until the mouse has moved past the global distance
|
||||
/// threshold (`io.mouse_drag_threshold`).
|
||||
///
|
||||
/// This is the same as [mouse_drag_delta_with_button](Self::mouse_drag_delta_with_button) with
|
||||
/// `button` set to `MouseButton::Left`.
|
||||
#[doc(alias = "GetMouseDragDelta")]
|
||||
pub fn mouse_drag_delta(&self) -> [f32; 2] {
|
||||
self.mouse_drag_delta_with_button(MouseButton::Left)
|
||||
}
|
||||
|
||||
/// Returns the delta from the initial position when the given button was clicked.
|
||||
///
|
||||
/// This is locked and returns [0.0, 0.0] until the mouse has moved past the global distance
|
||||
/// threshold (`io.mouse_drag_threshold`).
|
||||
///
|
||||
/// This is the same as [mouse_drag_delta_with_threshold](Self::mouse_drag_delta_with_threshold) with
|
||||
/// `threshold` set to `-1.0`, which uses the global threshold `io.mouse_drag_threshold`.
|
||||
#[doc(alias = "GetMouseDragDelta")]
|
||||
pub fn mouse_drag_delta_with_button(&self, button: MouseButton) -> [f32; 2] {
|
||||
self.mouse_drag_delta_with_threshold(button, -1.0)
|
||||
}
|
||||
/// Returns the delta from the initial clicking position.
|
||||
///
|
||||
/// This is locked and returns [0.0, 0.0] until the mouse has moved past the given threshold.
|
||||
/// If the given threshold is invalid or negative, the global distance threshold is used
|
||||
/// (`io.mouse_drag_threshold`).
|
||||
#[doc(alias = "GetMouseDragDelta")]
|
||||
pub fn mouse_drag_delta_with_threshold(&self, button: MouseButton, threshold: f32) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetMouseDragDelta(&mut out, button as i32, threshold) };
|
||||
out.into()
|
||||
}
|
||||
/// Resets the current delta from initial clicking position.
|
||||
#[doc(alias = "ResetMouseDragDelta")]
|
||||
pub fn reset_mouse_drag_delta(&self, button: MouseButton) {
|
||||
// This mutates the Io struct, but targets an internal field so there can't be any
|
||||
// references to it
|
||||
unsafe { sys::igResetMouseDragDelta(button as i32) }
|
||||
}
|
||||
/// Returns the currently desired mouse cursor type.
|
||||
///
|
||||
/// Returns `None` if no cursor should be displayed
|
||||
#[doc(alias = "GetMouseCursor")]
|
||||
pub fn mouse_cursor(&self) -> Option<MouseCursor> {
|
||||
match unsafe { sys::igGetMouseCursor() } {
|
||||
sys::ImGuiMouseCursor_Arrow => Some(MouseCursor::Arrow),
|
||||
sys::ImGuiMouseCursor_TextInput => Some(MouseCursor::TextInput),
|
||||
sys::ImGuiMouseCursor_ResizeAll => Some(MouseCursor::ResizeAll),
|
||||
sys::ImGuiMouseCursor_ResizeNS => Some(MouseCursor::ResizeNS),
|
||||
sys::ImGuiMouseCursor_ResizeEW => Some(MouseCursor::ResizeEW),
|
||||
sys::ImGuiMouseCursor_ResizeNESW => Some(MouseCursor::ResizeNESW),
|
||||
sys::ImGuiMouseCursor_ResizeNWSE => Some(MouseCursor::ResizeNWSE),
|
||||
sys::ImGuiMouseCursor_Hand => Some(MouseCursor::Hand),
|
||||
sys::ImGuiMouseCursor_NotAllowed => Some(MouseCursor::NotAllowed),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
/// Sets the desired mouse cursor type.
|
||||
///
|
||||
/// Passing `None` hides the mouse cursor.
|
||||
#[doc(alias = "SetMouseCursor")]
|
||||
pub fn set_mouse_cursor(&self, cursor_type: Option<MouseCursor>) {
|
||||
unsafe {
|
||||
sys::igSetMouseCursor(
|
||||
cursor_type
|
||||
.map(|x| x as i32)
|
||||
.unwrap_or(sys::ImGuiMouseCursor_None),
|
||||
);
|
||||
}
|
||||
}
|
||||
#[doc(alias = "IsMousePosValid")]
|
||||
pub fn is_current_mouse_pos_valid(&self) -> bool {
|
||||
unsafe { sys::igIsMousePosValid(ptr::null()) }
|
||||
}
|
||||
#[doc(alias = "IsMousePosValid")]
|
||||
pub fn is_mouse_pos_valid(&self, mouse_pos: [f32; 2]) -> bool {
|
||||
unsafe { sys::igIsMousePosValid(&mouse_pos.into()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_down_clicked_released() {
|
||||
for &button in MouseButton::VARIANTS.iter() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx_initialized();
|
||||
{
|
||||
ctx.io_mut().mouse_down = [false; 5];
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_down(button));
|
||||
assert!(!ui.is_any_mouse_down());
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_released(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_down(button));
|
||||
assert!(ui.is_any_mouse_down());
|
||||
assert!(ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_released(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_down(button));
|
||||
assert!(ui.is_any_mouse_down());
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_released(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = false;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_down(button));
|
||||
assert!(!ui.is_any_mouse_down());
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(ui.is_mouse_released(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_down(button));
|
||||
assert!(!ui.is_any_mouse_down());
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_released(button));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_double_click() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx_initialized();
|
||||
// Workaround for dear imgui bug/feature:
|
||||
// If a button is clicked before io.mouse_double_click_time seconds has passed after the
|
||||
// context is initialized, the single click is interpreted as a double-click. This happens
|
||||
// because internally g.IO.MouseClickedTime is set to 0.0, so the context creation is
|
||||
// considered a "click".
|
||||
{
|
||||
// Pass one second of time
|
||||
ctx.io_mut().delta_time = 1.0;
|
||||
let _ = ctx.frame();
|
||||
}
|
||||
// Fast clicks
|
||||
ctx.io_mut().delta_time = 1.0 / 60.0;
|
||||
for &button in MouseButton::VARIANTS.iter() {
|
||||
{
|
||||
ctx.io_mut().mouse_down = [false; 5];
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = false;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_clicked(button));
|
||||
assert!(ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
}
|
||||
// Slow clicks
|
||||
ctx.io_mut().delta_time = 1.0;
|
||||
for &button in MouseButton::VARIANTS.iter() {
|
||||
{
|
||||
ctx.io_mut().mouse_down = [false; 5];
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = false;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_get_mouse_cursor() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx_initialized();
|
||||
let ui = ctx.frame();
|
||||
ui.set_mouse_cursor(None);
|
||||
assert_eq!(None, ui.mouse_cursor());
|
||||
ui.set_mouse_cursor(Some(MouseCursor::Hand));
|
||||
assert_eq!(Some(MouseCursor::Hand), ui.mouse_cursor());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_drags() {
|
||||
for &button in MouseButton::VARIANTS.iter() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx_initialized();
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [0.0, 0.0];
|
||||
ctx.io_mut().mouse_down = [false; 5];
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_dragging(button));
|
||||
assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 0.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_dragging(button));
|
||||
assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 0.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [0.0, 100.0];
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_dragging(button));
|
||||
assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 100.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 0.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [0.0, 200.0];
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_dragging(button));
|
||||
assert!(ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 200.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 200.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [10.0, 10.0];
|
||||
ctx.io_mut()[button] = false;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_dragging(button));
|
||||
assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [10.0, 10.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[10.0, 10.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_dragging(button));
|
||||
assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 0.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [180.0, 180.0];
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_dragging(button));
|
||||
assert!(ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [170.0, 170.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[170.0, 170.0]
|
||||
);
|
||||
ui.reset_mouse_drag_delta(button);
|
||||
assert!(ui.is_mouse_dragging(button));
|
||||
assert!(ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 0.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [200.0, 200.0];
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_dragging(button));
|
||||
assert!(ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [20.0, 20.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[20.0, 20.0]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
1023
plugins/libimhex-rust/imgui-rs/src/input_widget.rs
vendored
Normal file
1023
plugins/libimhex-rust/imgui-rs/src/input_widget.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
159
plugins/libimhex-rust/imgui-rs/src/internal.rs
vendored
Normal file
159
plugins/libimhex-rust/imgui-rs/src/internal.rs
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
//! Internal raw utilities (don't use unless you know what you're doing!)
|
||||
|
||||
use std::slice;
|
||||
|
||||
/// A generic version of the raw imgui-sys ImVector struct types
|
||||
#[repr(C)]
|
||||
pub struct ImVector<T> {
|
||||
size: i32,
|
||||
capacity: i32,
|
||||
pub(crate) data: *mut T,
|
||||
}
|
||||
|
||||
impl<T> ImVector<T> {
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
unsafe { slice::from_raw_parts(self.data, self.size as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(test)]
|
||||
fn test_imvector_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(
|
||||
mem::size_of::<ImVector<u8>>(),
|
||||
mem::size_of::<sys::ImVector_char>()
|
||||
);
|
||||
assert_eq!(
|
||||
mem::align_of::<ImVector<u8>>(),
|
||||
mem::align_of::<sys::ImVector_char>()
|
||||
);
|
||||
use sys::ImVector_char;
|
||||
type VectorChar = ImVector<u8>;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(VectorChar, $l),
|
||||
memoffset::offset_of!(ImVector_char, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(size, Size);
|
||||
assert_field_offset!(capacity, Capacity);
|
||||
assert_field_offset!(data, Data);
|
||||
}
|
||||
|
||||
/// Marks a type as a transparent wrapper over a raw type
|
||||
pub trait RawWrapper {
|
||||
/// Wrapped raw type
|
||||
type Raw;
|
||||
/// Returns an immutable reference to the wrapped raw value
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to use the returned raw reference without causing undefined
|
||||
/// behaviour or breaking safety rules.
|
||||
unsafe fn raw(&self) -> &Self::Raw;
|
||||
/// Returns a mutable reference to the wrapped raw value
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to use the returned mutable raw reference without causing undefined
|
||||
/// behaviour or breaking safety rules.
|
||||
unsafe fn raw_mut(&mut self) -> &mut Self::Raw;
|
||||
}
|
||||
|
||||
/// Casting from/to a raw type that has the same layout and alignment as the target type
|
||||
pub unsafe trait RawCast<T>: Sized {
|
||||
/// Casts an immutable reference from the raw type
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the cast is valid.
|
||||
#[inline]
|
||||
unsafe fn from_raw(raw: &T) -> &Self {
|
||||
&*(raw as *const _ as *const Self)
|
||||
}
|
||||
/// Casts a mutable reference from the raw type
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the cast is valid.
|
||||
#[inline]
|
||||
unsafe fn from_raw_mut(raw: &mut T) -> &mut Self {
|
||||
&mut *(raw as *mut _ as *mut Self)
|
||||
}
|
||||
/// Casts an immutable reference to the raw type
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the cast is valid.
|
||||
#[inline]
|
||||
unsafe fn raw(&self) -> &T {
|
||||
&*(self as *const _ as *const T)
|
||||
}
|
||||
/// Casts a mutable reference to the raw type
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the cast is valid.
|
||||
#[inline]
|
||||
unsafe fn raw_mut(&mut self) -> &mut T {
|
||||
&mut *(self as *mut _ as *mut T)
|
||||
}
|
||||
}
|
||||
|
||||
/// A primary data type
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum DataType {
|
||||
I8 = sys::ImGuiDataType_S8,
|
||||
U8 = sys::ImGuiDataType_U8,
|
||||
I16 = sys::ImGuiDataType_S16,
|
||||
U16 = sys::ImGuiDataType_U16,
|
||||
I32 = sys::ImGuiDataType_S32,
|
||||
U32 = sys::ImGuiDataType_U32,
|
||||
I64 = sys::ImGuiDataType_S64,
|
||||
U64 = sys::ImGuiDataType_U64,
|
||||
F32 = sys::ImGuiDataType_Float,
|
||||
F64 = sys::ImGuiDataType_Double,
|
||||
}
|
||||
|
||||
/// Primitive type marker.
|
||||
///
|
||||
/// If this trait is implemented for a type, it is assumed to have *exactly* the same
|
||||
/// representation in memory as the primitive value described by the associated `KIND` constant.
|
||||
pub unsafe trait DataTypeKind: Copy {
|
||||
const KIND: DataType;
|
||||
}
|
||||
unsafe impl DataTypeKind for i8 {
|
||||
const KIND: DataType = DataType::I8;
|
||||
}
|
||||
unsafe impl DataTypeKind for u8 {
|
||||
const KIND: DataType = DataType::U8;
|
||||
}
|
||||
unsafe impl DataTypeKind for i16 {
|
||||
const KIND: DataType = DataType::I16;
|
||||
}
|
||||
unsafe impl DataTypeKind for u16 {
|
||||
const KIND: DataType = DataType::U16;
|
||||
}
|
||||
unsafe impl DataTypeKind for i32 {
|
||||
const KIND: DataType = DataType::I32;
|
||||
}
|
||||
unsafe impl DataTypeKind for u32 {
|
||||
const KIND: DataType = DataType::U32;
|
||||
}
|
||||
unsafe impl DataTypeKind for i64 {
|
||||
const KIND: DataType = DataType::I64;
|
||||
}
|
||||
unsafe impl DataTypeKind for u64 {
|
||||
const KIND: DataType = DataType::U64;
|
||||
}
|
||||
unsafe impl DataTypeKind for f32 {
|
||||
const KIND: DataType = DataType::F32;
|
||||
}
|
||||
unsafe impl DataTypeKind for f64 {
|
||||
const KIND: DataType = DataType::F64;
|
||||
}
|
||||
506
plugins/libimhex-rust/imgui-rs/src/io.rs
vendored
Normal file
506
plugins/libimhex-rust/imgui-rs/src/io.rs
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
use bitflags::bitflags;
|
||||
use std::f32;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::fonts::atlas::FontAtlas;
|
||||
use crate::fonts::font::Font;
|
||||
use crate::input::keyboard::Key;
|
||||
use crate::input::mouse::MouseButton;
|
||||
use crate::internal::{ImVector, RawCast};
|
||||
use crate::sys;
|
||||
|
||||
bitflags! {
|
||||
/// Configuration flags
|
||||
#[repr(transparent)]
|
||||
pub struct ConfigFlags: u32 {
|
||||
/// Master keyboard navigation enable flag.
|
||||
///
|
||||
/// `frame()` will automatically fill `io.nav_inputs` based on `io.keys_down`.
|
||||
const NAV_ENABLE_KEYBOARD = sys::ImGuiConfigFlags_NavEnableKeyboard;
|
||||
/// Master gamepad navigation enable flag.
|
||||
///
|
||||
/// This is mostly to instruct the backend to fill `io.nav_inputs`. The backend
|
||||
/// also needs to set `BackendFlags::HasGamepad`.
|
||||
const NAV_ENABLE_GAMEPAD = sys::ImGuiConfigFlags_NavEnableGamepad;
|
||||
/// Instruction navigation to move the mouse cursor.
|
||||
///
|
||||
/// May be useful on TV/console systems where moving a virtual mouse is awkward.
|
||||
/// Will update `io.mouse_pos` and set `io.want_set_mouse_pos = true`. If enabled,
|
||||
/// you *must* honor `io.want_set_mouse_pos`, or imgui-rs will react as if the mouse is
|
||||
/// jumping around back and forth.
|
||||
const NAV_ENABLE_SET_MOUSE_POS = sys::ImGuiConfigFlags_NavEnableSetMousePos;
|
||||
/// Instruction navigation to not set the `io.want_capture_keyboard` flag when
|
||||
/// `io.nav_active` is set.
|
||||
const NAV_NO_CAPTURE_KEYBOARD = sys::ImGuiConfigFlags_NavNoCaptureKeyboard;
|
||||
/// Instruction imgui-rs to clear mouse position/buttons in `frame()`.
|
||||
///
|
||||
/// This allows ignoring the mouse information set by the backend.
|
||||
const NO_MOUSE = sys::ImGuiConfigFlags_NoMouse;
|
||||
/// Instruction backend to not alter mouse cursor shape and visibility.
|
||||
///
|
||||
/// Use if the backend cursor changes are interfering with yours and you don't want to use
|
||||
/// `set_mouse_cursor` to change the mouse cursor. You may want to honor requests from
|
||||
/// imgui-rs by reading `get_mouse_cursor` yourself instead.
|
||||
const NO_MOUSE_CURSOR_CHANGE = sys::ImGuiConfigFlags_NoMouseCursorChange;
|
||||
/// Application is SRGB-aware.
|
||||
///
|
||||
/// Not used by core imgui-rs.
|
||||
const IS_SRGB = sys::ImGuiConfigFlags_IsSRGB;
|
||||
/// Application is using a touch screen instead of a mouse.
|
||||
///
|
||||
/// Not used by core imgui-rs.
|
||||
const IS_TOUCH_SCREEN = sys::ImGuiConfigFlags_IsTouchScreen;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Backend capabilities
|
||||
#[repr(transparent)]
|
||||
pub struct BackendFlags: u32 {
|
||||
/// Backend supports gamepad and currently has one connected
|
||||
const HAS_GAMEPAD = sys::ImGuiBackendFlags_HasGamepad;
|
||||
/// Backend supports honoring `get_mouse_cursor` value to change the OS cursor shape
|
||||
const HAS_MOUSE_CURSORS = sys::ImGuiBackendFlags_HasMouseCursors;
|
||||
/// Backend supports `io.want_set_mouse_pos` requests to reposition the OS mouse position.
|
||||
///
|
||||
/// Only used if `ConfigFlags::NavEnableSetMousePos` is set.
|
||||
const HAS_SET_MOUSE_POS = sys::ImGuiBackendFlags_HasSetMousePos;
|
||||
/// Backend renderer supports DrawCmd::vtx_offset.
|
||||
///
|
||||
/// This enables output of large meshes (64K+ vertices) while still using 16-bits indices.
|
||||
const RENDERER_HAS_VTX_OFFSET = sys::ImGuiBackendFlags_RendererHasVtxOffset;
|
||||
}
|
||||
}
|
||||
|
||||
/// An input identifier for navigation
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum NavInput {
|
||||
Activate = sys::ImGuiNavInput_Activate,
|
||||
Cancel = sys::ImGuiNavInput_Cancel,
|
||||
Input = sys::ImGuiNavInput_Input,
|
||||
Menu = sys::ImGuiNavInput_Menu,
|
||||
DpadLeft = sys::ImGuiNavInput_DpadLeft,
|
||||
DpadRight = sys::ImGuiNavInput_DpadRight,
|
||||
DpadUp = sys::ImGuiNavInput_DpadUp,
|
||||
DpadDown = sys::ImGuiNavInput_DpadDown,
|
||||
LStickLeft = sys::ImGuiNavInput_LStickLeft,
|
||||
LStickRight = sys::ImGuiNavInput_LStickRight,
|
||||
LStickUp = sys::ImGuiNavInput_LStickUp,
|
||||
LStickDown = sys::ImGuiNavInput_LStickDown,
|
||||
FocusPrev = sys::ImGuiNavInput_FocusPrev,
|
||||
FocusNext = sys::ImGuiNavInput_FocusNext,
|
||||
TweakSlow = sys::ImGuiNavInput_TweakSlow,
|
||||
TweakFast = sys::ImGuiNavInput_TweakFast,
|
||||
}
|
||||
|
||||
impl NavInput {
|
||||
/// All possible `NavInput` variants
|
||||
pub const VARIANTS: [NavInput; NavInput::COUNT] = [
|
||||
NavInput::Activate,
|
||||
NavInput::Cancel,
|
||||
NavInput::Input,
|
||||
NavInput::Menu,
|
||||
NavInput::DpadLeft,
|
||||
NavInput::DpadRight,
|
||||
NavInput::DpadUp,
|
||||
NavInput::DpadDown,
|
||||
NavInput::LStickLeft,
|
||||
NavInput::LStickRight,
|
||||
NavInput::LStickUp,
|
||||
NavInput::LStickDown,
|
||||
NavInput::FocusPrev,
|
||||
NavInput::FocusNext,
|
||||
NavInput::TweakSlow,
|
||||
NavInput::TweakFast,
|
||||
];
|
||||
/// Amount of internal/hidden variants (not exposed by imgui-rs)
|
||||
const INTERNAL_COUNT: usize = 4;
|
||||
/// Total count of `NavInput` variants
|
||||
pub const COUNT: usize = sys::ImGuiNavInput_COUNT as usize - NavInput::INTERNAL_COUNT;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nav_input_variants() {
|
||||
for (idx, &value) in NavInput::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
|
||||
/// Settings and inputs/outputs for imgui-rs
|
||||
#[repr(C)]
|
||||
pub struct Io {
|
||||
/// Flags set by user/application
|
||||
pub config_flags: ConfigFlags,
|
||||
/// Flags set by backend
|
||||
pub backend_flags: BackendFlags,
|
||||
/// Main display size in pixels
|
||||
pub display_size: [f32; 2],
|
||||
/// Time elapsed since last frame, in seconds
|
||||
pub delta_time: f32,
|
||||
/// Minimum time between saving positions/sizes to .ini file, in seconds
|
||||
pub ini_saving_rate: f32,
|
||||
|
||||
pub(crate) ini_filename: *const c_char,
|
||||
pub(crate) log_filename: *const c_char,
|
||||
|
||||
/// Time for a double-click, in seconds
|
||||
pub mouse_double_click_time: f32,
|
||||
/// Distance threshold to stay in to validate a double-click, in pixels
|
||||
pub mouse_double_click_max_dist: f32,
|
||||
/// Distance threshold before considering we are dragging
|
||||
pub mouse_drag_threshold: f32,
|
||||
/// Map of indices into the `keys_down` entries array, which represent your "native" keyboard
|
||||
/// state
|
||||
pub key_map: [u32; sys::ImGuiKey_COUNT as usize],
|
||||
/// When holding a key/button, time before it starts repeating, in seconds
|
||||
pub key_repeat_delay: f32,
|
||||
/// When holding a key/button, rate at which it repeats, in seconds
|
||||
pub key_repeat_rate: f32,
|
||||
|
||||
user_data: *mut c_void,
|
||||
pub(crate) fonts: *mut FontAtlas,
|
||||
|
||||
/// Global scale for all fonts
|
||||
pub font_global_scale: f32,
|
||||
/// Allow user to scale text of individual window with CTRL+wheel
|
||||
pub font_allow_user_scaling: bool,
|
||||
|
||||
pub(crate) font_default: *mut Font,
|
||||
|
||||
/// For retina display or other situations where window coordinates are different from
|
||||
/// framebuffer coordinates
|
||||
pub display_framebuffer_scale: [f32; 2],
|
||||
|
||||
/// Request imgui-rs to draw a mouse cursor for you
|
||||
pub mouse_draw_cursor: bool,
|
||||
/// macOS-style input behavior.
|
||||
///
|
||||
/// Defaults to true on Apple platforms. Changes in behavior:
|
||||
///
|
||||
/// * Text editing cursor movement using Alt instead of Ctrl
|
||||
/// * Shortcuts using Cmd/Super instead of Ctrl
|
||||
/// * Line/text start and end using Cmd+Arrows instead of Home/End
|
||||
/// * Double-click selects by word instead of selecting the whole text
|
||||
/// * Multi-selection in lists uses Cmd/Super instead of Ctrl
|
||||
pub config_mac_os_behaviors: bool,
|
||||
/// Set to false to disable blinking cursor
|
||||
pub config_input_text_cursor_blink: bool,
|
||||
/// Enable turning DragXXX widgets into text input with a simple mouse
|
||||
/// click-release (without moving). Not desirable on devices without a
|
||||
/// keyboard.
|
||||
pub config_drag_click_to_input_text: bool,
|
||||
/// Enable resizing of windows from their edges and from the lower-left corner.
|
||||
///
|
||||
/// Requires `HasMouserCursors` in `backend_flags`, because it needs mouse cursor feedback.
|
||||
pub config_windows_resize_from_edges: bool,
|
||||
/// Set to true to only allow moving windows when clicked+dragged from the title bar.
|
||||
///
|
||||
/// Windows without a title bar are not affected.
|
||||
pub config_windows_move_from_title_bar_only: bool,
|
||||
/// Compact memory usage when unused.
|
||||
///
|
||||
/// Set to -1.0 to disable.
|
||||
pub config_memory_compact_timer: f32,
|
||||
|
||||
pub(crate) backend_platform_name: *const c_char,
|
||||
pub(crate) backend_renderer_name: *const c_char,
|
||||
backend_platform_user_data: *mut c_void,
|
||||
backend_renderer_user_data: *mut c_void,
|
||||
backend_language_user_data: *mut c_void,
|
||||
pub(crate) get_clipboard_text_fn:
|
||||
Option<unsafe extern "C" fn(user_data: *mut c_void) -> *const c_char>,
|
||||
pub(crate) set_clipboard_text_fn:
|
||||
Option<unsafe extern "C" fn(user_data: *mut c_void, text: *const c_char)>,
|
||||
pub(crate) clipboard_user_data: *mut c_void,
|
||||
ime_set_input_screen_pos_fn: Option<unsafe extern "C" fn(x: c_int, y: c_int)>,
|
||||
ime_window_handle: *mut c_void,
|
||||
/// Mouse position, in pixels.
|
||||
///
|
||||
/// Set to [f32::MAX, f32::MAX] if mouse is unavailable (on another screen, etc.).
|
||||
pub mouse_pos: [f32; 2],
|
||||
/// Mouse buttons: 0=left, 1=right, 2=middle + extras
|
||||
pub mouse_down: [bool; 5],
|
||||
/// Mouse wheel (vertical).
|
||||
///
|
||||
/// 1 unit scrolls about 5 lines of text.
|
||||
pub mouse_wheel: f32,
|
||||
/// Mouse wheel (horizontal).
|
||||
///
|
||||
/// Most users don't have a mouse with a horizontal wheel, and may not be filled by all
|
||||
/// backends.
|
||||
pub mouse_wheel_h: f32,
|
||||
/// Keyboard modifier pressed: Control
|
||||
pub key_ctrl: bool,
|
||||
/// Keyboard modifier pressed: Shift
|
||||
pub key_shift: bool,
|
||||
/// Keyboard modifier pressed: Alt
|
||||
pub key_alt: bool,
|
||||
/// Keyboard modifier pressed: Cmd/Super/Windows
|
||||
pub key_super: bool,
|
||||
/// Keyboard keys that are pressed (indexing defined by the user/application)
|
||||
pub keys_down: [bool; 512],
|
||||
/// Gamepad inputs.
|
||||
///
|
||||
/// Cleared back to zero after each frame. Keyboard keys will be auto-mapped and written
|
||||
/// here by `frame()`.
|
||||
pub nav_inputs: [f32; NavInput::COUNT + NavInput::INTERNAL_COUNT],
|
||||
/// When true, imgui-rs will use the mouse inputs, so do not dispatch them to your main
|
||||
/// game/application
|
||||
pub want_capture_mouse: bool,
|
||||
/// When true, imgui-rs will use the keyboard inputs, so do not dispatch them to your main
|
||||
/// game/application
|
||||
pub want_capture_keyboard: bool,
|
||||
/// Mobile/console: when true, you may display an on-screen keyboard.
|
||||
///
|
||||
/// This is set by imgui-rs when it wants textual keyboard input to happen.
|
||||
pub want_text_input: bool,
|
||||
/// Mouse position has been altered, so the backend should reposition the mouse on the next
|
||||
/// frame.
|
||||
///
|
||||
/// Set only when `ConfigFlags::NavEnableSetMousePos` is enabled.
|
||||
pub want_set_mouse_pos: bool,
|
||||
/// When manual .ini load/save is active (`ini_filename` is `None`), this will be set to notify
|
||||
/// your application that you can call `save_ini_settings` and save the settings yourself.
|
||||
///
|
||||
/// *Important*: You need to clear this flag yourself
|
||||
pub want_save_ini_settings: bool,
|
||||
/// Keyboard/Gamepad navigation is currently allowed
|
||||
pub nav_active: bool,
|
||||
/// Keyboard/Gamepad navigation is visible and allowed
|
||||
pub nav_visible: bool,
|
||||
/// Application framerate estimation, in frames per second.
|
||||
///
|
||||
/// Rolling average estimation based on `io.delta_time` over 120 frames.
|
||||
pub framerate: f32,
|
||||
/// Vertices output during last rendering
|
||||
pub metrics_render_vertices: i32,
|
||||
/// Indices output during last rendering (= number of triangles * 3)
|
||||
pub metrics_render_indices: i32,
|
||||
/// Number of visible windows
|
||||
pub metrics_render_windows: i32,
|
||||
/// Number of active windows
|
||||
pub metrics_active_windows: i32,
|
||||
/// Number of active internal imgui-rs allocations
|
||||
pub metrics_active_allocations: i32,
|
||||
/// Mouse delta.
|
||||
///
|
||||
/// Note that this is zero if either current or previous position is invalid ([f32::MAX,
|
||||
/// f32::MAX]), so a disappearing/reappearing mouse won't have a huge delta.
|
||||
pub mouse_delta: [f32; 2],
|
||||
|
||||
key_mods: sys::ImGuiKeyModFlags,
|
||||
key_mods_prev: sys::ImGuiKeyModFlags,
|
||||
mouse_pos_prev: [f32; 2],
|
||||
mouse_clicked_pos: [[f32; 2]; 5],
|
||||
mouse_clicked_time: [f64; 5],
|
||||
mouse_clicked: [bool; 5],
|
||||
mouse_double_clicked: [bool; 5],
|
||||
mouse_released: [bool; 5],
|
||||
mouse_down_owned: [bool; 5],
|
||||
mouse_down_was_double_click: [bool; 5],
|
||||
mouse_down_duration: [f32; 5],
|
||||
mouse_down_duration_prev: [f32; 5],
|
||||
mouse_drag_max_distance_abs: [[f32; 2]; 5],
|
||||
mouse_drag_max_distance_sqr: [f32; 5],
|
||||
keys_down_duration: [f32; 512],
|
||||
keys_down_duration_prev: [f32; 512],
|
||||
nav_inputs_down_duration: [f32; NavInput::COUNT + NavInput::INTERNAL_COUNT],
|
||||
nav_inputs_down_duration_prev: [f32; NavInput::COUNT + NavInput::INTERNAL_COUNT],
|
||||
pen_pressure: f32,
|
||||
input_queue_surrogate: sys::ImWchar16,
|
||||
input_queue_characters: ImVector<sys::ImWchar>,
|
||||
}
|
||||
|
||||
unsafe impl RawCast<sys::ImGuiIO> for Io {}
|
||||
|
||||
impl Io {
|
||||
/// Queue new character input
|
||||
#[doc(alias = "AddInputCharactersUTF8")]
|
||||
pub fn add_input_character(&mut self, character: char) {
|
||||
let mut buf = [0; 5];
|
||||
character.encode_utf8(&mut buf);
|
||||
unsafe {
|
||||
sys::ImGuiIO_AddInputCharactersUTF8(self.raw_mut(), buf.as_ptr() as *const _);
|
||||
}
|
||||
}
|
||||
/// Clear character input buffer
|
||||
#[doc(alias = "ClearCharacters")]
|
||||
pub fn clear_input_characters(&mut self) {
|
||||
unsafe {
|
||||
sys::ImGuiIO_ClearInputCharacters(self.raw_mut());
|
||||
}
|
||||
}
|
||||
/// Peek character input buffer, return a copy of entire buffer
|
||||
pub fn peek_input_characters(&self) -> String {
|
||||
self.input_queue_characters().collect()
|
||||
}
|
||||
|
||||
/// Returns a view of the data in the input queue (without copying it).
|
||||
///
|
||||
/// The returned iterator is a simple mapping over a slice more or less what
|
||||
/// you need for random access to the data (Rust has no
|
||||
/// `RandomAccessIterator`, or we'd use that).
|
||||
pub fn input_queue_characters(
|
||||
&self,
|
||||
) -> impl Iterator<Item = char> + DoubleEndedIterator + ExactSizeIterator + Clone + '_ {
|
||||
self.input_queue_characters
|
||||
.as_slice()
|
||||
.iter()
|
||||
// TODO: are the values in the buffer guaranteed to be valid unicode
|
||||
// scalar values? if so we can just expose this as a `&[char]`...
|
||||
.map(|c| core::char::from_u32(*c).unwrap_or(core::char::REPLACEMENT_CHARACTER))
|
||||
}
|
||||
|
||||
pub fn update_delta_time(&mut self, delta: Duration) {
|
||||
let delta_s = delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1_000_000_000.0;
|
||||
if delta_s > 0.0 {
|
||||
self.delta_time = delta_s;
|
||||
} else {
|
||||
self.delta_time = f32::MIN_POSITIVE;
|
||||
}
|
||||
self.delta_time = delta_s;
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<Key> for Io {
|
||||
type Output = u32;
|
||||
fn index(&self, index: Key) -> &u32 {
|
||||
&self.key_map[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<Key> for Io {
|
||||
fn index_mut(&mut self, index: Key) -> &mut u32 {
|
||||
&mut self.key_map[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<NavInput> for Io {
|
||||
type Output = f32;
|
||||
fn index(&self, index: NavInput) -> &f32 {
|
||||
&self.nav_inputs[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<NavInput> for Io {
|
||||
fn index_mut(&mut self, index: NavInput) -> &mut f32 {
|
||||
&mut self.nav_inputs[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<MouseButton> for Io {
|
||||
type Output = bool;
|
||||
fn index(&self, index: MouseButton) -> &bool {
|
||||
&self.mouse_down[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<MouseButton> for Io {
|
||||
fn index_mut(&mut self, index: MouseButton) -> &mut bool {
|
||||
&mut self.mouse_down[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(test)]
|
||||
fn test_io_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(mem::size_of::<Io>(), mem::size_of::<sys::ImGuiIO>());
|
||||
assert_eq!(mem::align_of::<Io>(), mem::align_of::<sys::ImGuiIO>());
|
||||
use sys::ImGuiIO;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(Io, $l),
|
||||
memoffset::offset_of!(ImGuiIO, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(config_flags, ConfigFlags);
|
||||
assert_field_offset!(backend_flags, BackendFlags);
|
||||
assert_field_offset!(display_size, DisplaySize);
|
||||
assert_field_offset!(delta_time, DeltaTime);
|
||||
assert_field_offset!(ini_saving_rate, IniSavingRate);
|
||||
assert_field_offset!(ini_filename, IniFilename);
|
||||
assert_field_offset!(log_filename, LogFilename);
|
||||
assert_field_offset!(mouse_double_click_time, MouseDoubleClickTime);
|
||||
assert_field_offset!(mouse_double_click_max_dist, MouseDoubleClickMaxDist);
|
||||
assert_field_offset!(mouse_drag_threshold, MouseDragThreshold);
|
||||
assert_field_offset!(key_map, KeyMap);
|
||||
assert_field_offset!(key_repeat_delay, KeyRepeatDelay);
|
||||
assert_field_offset!(key_repeat_rate, KeyRepeatRate);
|
||||
assert_field_offset!(user_data, UserData);
|
||||
assert_field_offset!(fonts, Fonts);
|
||||
assert_field_offset!(font_global_scale, FontGlobalScale);
|
||||
assert_field_offset!(font_allow_user_scaling, FontAllowUserScaling);
|
||||
assert_field_offset!(font_default, FontDefault);
|
||||
assert_field_offset!(display_framebuffer_scale, DisplayFramebufferScale);
|
||||
assert_field_offset!(mouse_draw_cursor, MouseDrawCursor);
|
||||
assert_field_offset!(config_mac_os_behaviors, ConfigMacOSXBehaviors);
|
||||
assert_field_offset!(config_input_text_cursor_blink, ConfigInputTextCursorBlink);
|
||||
assert_field_offset!(
|
||||
config_windows_resize_from_edges,
|
||||
ConfigWindowsResizeFromEdges
|
||||
);
|
||||
assert_field_offset!(
|
||||
config_windows_move_from_title_bar_only,
|
||||
ConfigWindowsMoveFromTitleBarOnly
|
||||
);
|
||||
assert_field_offset!(backend_platform_name, BackendPlatformName);
|
||||
assert_field_offset!(backend_renderer_name, BackendRendererName);
|
||||
assert_field_offset!(backend_platform_user_data, BackendPlatformUserData);
|
||||
assert_field_offset!(backend_renderer_user_data, BackendRendererUserData);
|
||||
assert_field_offset!(backend_language_user_data, BackendLanguageUserData);
|
||||
assert_field_offset!(get_clipboard_text_fn, GetClipboardTextFn);
|
||||
assert_field_offset!(set_clipboard_text_fn, SetClipboardTextFn);
|
||||
assert_field_offset!(clipboard_user_data, ClipboardUserData);
|
||||
assert_field_offset!(ime_set_input_screen_pos_fn, ImeSetInputScreenPosFn);
|
||||
assert_field_offset!(ime_window_handle, ImeWindowHandle);
|
||||
assert_field_offset!(mouse_pos, MousePos);
|
||||
assert_field_offset!(mouse_down, MouseDown);
|
||||
assert_field_offset!(mouse_wheel, MouseWheel);
|
||||
assert_field_offset!(mouse_wheel_h, MouseWheelH);
|
||||
assert_field_offset!(key_ctrl, KeyCtrl);
|
||||
assert_field_offset!(key_shift, KeyShift);
|
||||
assert_field_offset!(key_alt, KeyAlt);
|
||||
assert_field_offset!(key_super, KeySuper);
|
||||
assert_field_offset!(keys_down, KeysDown);
|
||||
assert_field_offset!(nav_inputs, NavInputs);
|
||||
assert_field_offset!(want_capture_mouse, WantCaptureMouse);
|
||||
assert_field_offset!(want_capture_keyboard, WantCaptureKeyboard);
|
||||
assert_field_offset!(want_text_input, WantTextInput);
|
||||
assert_field_offset!(want_set_mouse_pos, WantSetMousePos);
|
||||
assert_field_offset!(want_save_ini_settings, WantSaveIniSettings);
|
||||
assert_field_offset!(nav_active, NavActive);
|
||||
assert_field_offset!(nav_visible, NavVisible);
|
||||
assert_field_offset!(framerate, Framerate);
|
||||
assert_field_offset!(metrics_render_vertices, MetricsRenderVertices);
|
||||
assert_field_offset!(metrics_render_indices, MetricsRenderIndices);
|
||||
assert_field_offset!(metrics_render_windows, MetricsRenderWindows);
|
||||
assert_field_offset!(metrics_active_windows, MetricsActiveWindows);
|
||||
assert_field_offset!(metrics_active_allocations, MetricsActiveAllocations);
|
||||
assert_field_offset!(mouse_delta, MouseDelta);
|
||||
assert_field_offset!(key_mods, KeyMods);
|
||||
assert_field_offset!(mouse_pos_prev, MousePosPrev);
|
||||
assert_field_offset!(mouse_clicked_pos, MouseClickedPos);
|
||||
assert_field_offset!(mouse_clicked_time, MouseClickedTime);
|
||||
assert_field_offset!(mouse_clicked, MouseClicked);
|
||||
assert_field_offset!(mouse_double_clicked, MouseDoubleClicked);
|
||||
assert_field_offset!(mouse_released, MouseReleased);
|
||||
assert_field_offset!(mouse_down_owned, MouseDownOwned);
|
||||
assert_field_offset!(mouse_down_was_double_click, MouseDownWasDoubleClick);
|
||||
assert_field_offset!(mouse_down_duration, MouseDownDuration);
|
||||
assert_field_offset!(mouse_down_duration_prev, MouseDownDurationPrev);
|
||||
assert_field_offset!(mouse_drag_max_distance_abs, MouseDragMaxDistanceAbs);
|
||||
assert_field_offset!(mouse_drag_max_distance_sqr, MouseDragMaxDistanceSqr);
|
||||
assert_field_offset!(keys_down_duration, KeysDownDuration);
|
||||
assert_field_offset!(keys_down_duration_prev, KeysDownDurationPrev);
|
||||
assert_field_offset!(nav_inputs_down_duration, NavInputsDownDuration);
|
||||
assert_field_offset!(nav_inputs_down_duration_prev, NavInputsDownDurationPrev);
|
||||
assert_field_offset!(pen_pressure, PenPressure);
|
||||
assert_field_offset!(input_queue_surrogate, InputQueueSurrogate);
|
||||
assert_field_offset!(input_queue_characters, InputQueueCharacters);
|
||||
}
|
||||
176
plugins/libimhex-rust/imgui-rs/src/layout.rs
vendored
Normal file
176
plugins/libimhex-rust/imgui-rs/src/layout.rs
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
create_token!(
|
||||
/// Tracks a layout group that can be ended with `end` or by dropping.
|
||||
pub struct GroupToken<'ui>;
|
||||
|
||||
/// Drops the layout group manually. You can also just allow this token
|
||||
/// to drop on its own.
|
||||
drop { sys::igEndGroup() }
|
||||
);
|
||||
|
||||
/// # Cursor / Layout
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Renders a separator (generally horizontal).
|
||||
///
|
||||
/// This becomes a vertical separator inside a menu bar or in horizontal layout mode.
|
||||
#[doc(alias = "Separator")]
|
||||
pub fn separator(&self) {
|
||||
unsafe { sys::igSeparator() }
|
||||
}
|
||||
|
||||
/// Call between widgets or groups to layout them horizontally.
|
||||
///
|
||||
/// X position is given in window coordinates.
|
||||
///
|
||||
/// This is equivalent to calling [same_line_with_pos](Self::same_line_with_pos)
|
||||
/// with the `pos` set to 0.0, which uses `Style::item_spacing`.
|
||||
#[doc(alias = "SameLine")]
|
||||
pub fn same_line(&self) {
|
||||
self.same_line_with_pos(0.0);
|
||||
}
|
||||
|
||||
/// Call between widgets or groups to layout them horizontally.
|
||||
///
|
||||
/// X position is given in window coordinates.
|
||||
///
|
||||
/// This is equivalent to calling [same_line_with_spacing](Self::same_line_with_spacing)
|
||||
/// with the `spacing` set to -1.0, which means no extra spacing.
|
||||
#[doc(alias = "SameLine")]
|
||||
pub fn same_line_with_pos(&self, pos_x: f32) {
|
||||
self.same_line_with_spacing(pos_x, -1.0)
|
||||
}
|
||||
|
||||
/// Call between widgets or groups to layout them horizontally.
|
||||
///
|
||||
/// X position is given in window coordinates.
|
||||
#[doc(alias = "SameLine")]
|
||||
pub fn same_line_with_spacing(&self, pos_x: f32, spacing_w: f32) {
|
||||
unsafe { sys::igSameLine(pos_x, spacing_w) }
|
||||
}
|
||||
|
||||
/// Undo a `same_line` call or force a new line when in horizontal layout mode
|
||||
#[doc(alias = "NewLine")]
|
||||
pub fn new_line(&self) {
|
||||
unsafe { sys::igNewLine() }
|
||||
}
|
||||
/// Adds vertical spacing
|
||||
#[doc(alias = "Spacing")]
|
||||
pub fn spacing(&self) {
|
||||
unsafe { sys::igSpacing() }
|
||||
}
|
||||
/// Fills a space of `size` in pixels with nothing on the current window.
|
||||
///
|
||||
/// Can be used to move the cursor on the window.
|
||||
#[doc(alias = "Dummy")]
|
||||
pub fn dummy(&self, size: [f32; 2]) {
|
||||
unsafe { sys::igDummy(size.into()) }
|
||||
}
|
||||
|
||||
/// Moves content position to the right by `Style::indent_spacing`
|
||||
///
|
||||
/// This is equivalent to [indent_by](Self::indent_by) with `width` set to
|
||||
/// `Style::ident_spacing`.
|
||||
#[doc(alias = "Indent")]
|
||||
pub fn indent(&self) {
|
||||
self.indent_by(0.0)
|
||||
}
|
||||
|
||||
/// Moves content position to the right by `width`
|
||||
#[doc(alias = "Indent")]
|
||||
pub fn indent_by(&self, width: f32) {
|
||||
unsafe { sys::igIndent(width) };
|
||||
}
|
||||
/// Moves content position to the left by `Style::indent_spacing`
|
||||
///
|
||||
/// This is equivalent to [unindent_by](Self::unindent_by) with `width` set to
|
||||
/// `Style::ident_spacing`.
|
||||
#[doc(alias = "Unindent")]
|
||||
pub fn unindent(&self) {
|
||||
self.unindent_by(0.0)
|
||||
}
|
||||
/// Moves content position to the left by `width`
|
||||
#[doc(alias = "Unindent")]
|
||||
pub fn unindent_by(&self, width: f32) {
|
||||
unsafe { sys::igUnindent(width) };
|
||||
}
|
||||
/// Groups items together as a single item.
|
||||
///
|
||||
/// May be useful to handle the same mouse event on a group of items, for example.
|
||||
///
|
||||
/// Returns a `GroupToken` that must be ended by calling `.end()`
|
||||
#[doc(alias = "BeginGroup")]
|
||||
pub fn begin_group(&self) -> GroupToken<'_> {
|
||||
unsafe { sys::igBeginGroup() };
|
||||
GroupToken::new(self)
|
||||
}
|
||||
/// Creates a layout group and runs a closure to construct the contents.
|
||||
///
|
||||
/// May be useful to handle the same mouse event on a group of items, for example.
|
||||
#[doc(alias = "BeginGroup")]
|
||||
pub fn group<R, F: FnOnce() -> R>(&self, f: F) -> R {
|
||||
let group = self.begin_group();
|
||||
let result = f();
|
||||
group.end();
|
||||
result
|
||||
}
|
||||
/// Returns the cursor position (in window coordinates)
|
||||
#[doc(alias = "GetCursorPos")]
|
||||
pub fn cursor_pos(&self) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetCursorPos(&mut out) };
|
||||
out.into()
|
||||
}
|
||||
/// Sets the cursor position (in window coordinates).
|
||||
///
|
||||
/// This sets the point on which the next widget will be drawn.
|
||||
#[doc(alias = "SetCursorPos")]
|
||||
pub fn set_cursor_pos(&self, pos: [f32; 2]) {
|
||||
unsafe { sys::igSetCursorPos(pos.into()) };
|
||||
}
|
||||
/// Returns the initial cursor position (in window coordinates)
|
||||
#[doc(alias = "GetCursorStartPos")]
|
||||
pub fn cursor_start_pos(&self) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetCursorStartPos(&mut out) };
|
||||
out.into()
|
||||
}
|
||||
/// Returns the cursor position (in absolute screen coordinates).
|
||||
///
|
||||
/// This is especially useful for drawing, as the drawing API uses screen coordinates.
|
||||
#[doc(alias = "GetCursorScreenPos")]
|
||||
pub fn cursor_screen_pos(&self) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetCursorScreenPos(&mut out) };
|
||||
out.into()
|
||||
}
|
||||
/// Sets the cursor position (in absolute screen coordinates)
|
||||
#[doc(alias = "SetCursorScreenPos")]
|
||||
pub fn set_cursor_screen_pos(&self, pos: [f32; 2]) {
|
||||
unsafe { sys::igSetCursorScreenPos(pos.into()) }
|
||||
}
|
||||
/// Vertically aligns text baseline so that it will align properly to regularly frame items.
|
||||
///
|
||||
/// Call this if you have text on a line before a framed item.
|
||||
#[doc(alias = "AlignTextToFramePadding")]
|
||||
pub fn align_text_to_frame_padding(&self) {
|
||||
unsafe { sys::igAlignTextToFramePadding() };
|
||||
}
|
||||
#[doc(alias = "GetTextLineHeight")]
|
||||
pub fn text_line_height(&self) -> f32 {
|
||||
unsafe { sys::igGetTextLineHeight() }
|
||||
}
|
||||
#[doc(alias = "GetTextLineHeightWithSpacing")]
|
||||
pub fn text_line_height_with_spacing(&self) -> f32 {
|
||||
unsafe { sys::igGetTextLineHeightWithSpacing() }
|
||||
}
|
||||
#[doc(alias = "GetFrameHeight")]
|
||||
pub fn frame_height(&self) -> f32 {
|
||||
unsafe { sys::igGetFrameHeight() }
|
||||
}
|
||||
#[doc(alias = "GetFrameLineHeightWithSpacing")]
|
||||
pub fn frame_height_with_spacing(&self) -> f32 {
|
||||
unsafe { sys::igGetFrameHeightWithSpacing() }
|
||||
}
|
||||
}
|
||||
753
plugins/libimhex-rust/imgui-rs/src/lib.rs
vendored
Normal file
753
plugins/libimhex-rust/imgui-rs/src/lib.rs
vendored
Normal file
@@ -0,0 +1,753 @@
|
||||
#![cfg_attr(test, allow(clippy::float_cmp))]
|
||||
#![deny(rust_2018_idioms)]
|
||||
// #![deny(missing_docs)]
|
||||
|
||||
pub extern crate imgui_sys as sys;
|
||||
|
||||
use std::cell;
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
use std::thread;
|
||||
|
||||
pub use self::clipboard::*;
|
||||
pub use self::color::ImColor32;
|
||||
pub use self::context::*;
|
||||
pub use self::drag_drop::{DragDropFlags, DragDropSource, DragDropTarget};
|
||||
pub use self::draw_list::{ChannelsSplit, DrawListMut};
|
||||
pub use self::fonts::atlas::*;
|
||||
pub use self::fonts::font::*;
|
||||
pub use self::fonts::glyph::*;
|
||||
pub use self::fonts::glyph_ranges::*;
|
||||
pub use self::input::keyboard::*;
|
||||
pub use self::input::mouse::*;
|
||||
pub use self::input_widget::*;
|
||||
pub use self::io::*;
|
||||
pub use self::layout::*;
|
||||
pub use self::list_clipper::ListClipper;
|
||||
pub use self::plothistogram::PlotHistogram;
|
||||
pub use self::plotlines::PlotLines;
|
||||
pub use self::popups::*;
|
||||
pub use self::render::draw_data::*;
|
||||
pub use self::render::renderer::*;
|
||||
pub use self::stacks::*;
|
||||
pub use self::string::*;
|
||||
pub use self::style::*;
|
||||
|
||||
#[cfg(feature = "tables-api")]
|
||||
pub use self::tables::*;
|
||||
pub use self::utils::*;
|
||||
pub use self::widget::color_editors::*;
|
||||
pub use self::widget::combo_box::*;
|
||||
pub use self::widget::drag::*;
|
||||
pub use self::widget::image::*;
|
||||
pub use self::widget::list_box::*;
|
||||
pub use self::widget::menu::*;
|
||||
pub use self::widget::misc::*;
|
||||
pub use self::widget::progress_bar::*;
|
||||
pub use self::widget::selectable::*;
|
||||
pub use self::widget::slider::*;
|
||||
pub use self::widget::tab::*;
|
||||
pub use self::widget::tree::*;
|
||||
pub use self::window::child_window::*;
|
||||
pub use self::window::*;
|
||||
use internal::RawCast;
|
||||
|
||||
#[macro_use]
|
||||
mod string;
|
||||
|
||||
#[macro_use]
|
||||
mod tokens;
|
||||
|
||||
mod clipboard;
|
||||
pub mod color;
|
||||
mod columns;
|
||||
mod context;
|
||||
pub mod drag_drop;
|
||||
pub mod draw_list;
|
||||
mod fonts;
|
||||
mod input;
|
||||
mod input_widget;
|
||||
pub mod internal;
|
||||
mod io;
|
||||
mod layout;
|
||||
mod list_clipper;
|
||||
mod plothistogram;
|
||||
mod plotlines;
|
||||
mod popups;
|
||||
mod render;
|
||||
mod stacks;
|
||||
mod style;
|
||||
#[cfg(feature = "tables-api")]
|
||||
mod tables;
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
mod utils;
|
||||
mod widget;
|
||||
mod window;
|
||||
|
||||
// Used by macros. Underscores are just to make it clear it's not part of the
|
||||
// public API.
|
||||
#[doc(hidden)]
|
||||
pub use core as __core;
|
||||
|
||||
/// Returns the underlying Dear ImGui library version
|
||||
#[doc(alias = "GetVersion")]
|
||||
pub fn dear_imgui_version() -> &'static str {
|
||||
unsafe {
|
||||
let bytes = CStr::from_ptr(sys::igGetVersion()).to_bytes();
|
||||
str::from_utf8_unchecked(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Returns the global imgui-rs time.
|
||||
///
|
||||
/// Incremented by Io::delta_time every frame.
|
||||
#[doc(alias = "GetTime")]
|
||||
pub fn time(&self) -> f64 {
|
||||
unsafe { sys::igGetTime() }
|
||||
}
|
||||
/// Returns the global imgui-rs frame count.
|
||||
///
|
||||
/// Incremented by 1 every frame.
|
||||
#[doc(alias = "GetFrameCount")]
|
||||
pub fn frame_count(&self) -> i32 {
|
||||
unsafe { sys::igGetFrameCount() }
|
||||
}
|
||||
}
|
||||
|
||||
/// A temporary reference for building the user interface for one frame
|
||||
#[derive(Debug)]
|
||||
pub struct Ui<'ui> {
|
||||
ctx: &'ui Context,
|
||||
font_atlas: Option<cell::RefMut<'ui, SharedFontAtlas>>,
|
||||
// imgui isn't mutli-threaded -- so no one will ever access twice.
|
||||
buffer: cell::UnsafeCell<string::UiBuffer>,
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Internal method to push a single text to our scratch buffer.
|
||||
fn scratch_txt(&self, txt: impl AsRef<str>) -> *const sys::cty::c_char {
|
||||
unsafe {
|
||||
let handle = &mut *self.buffer.get();
|
||||
handle.scratch_txt(txt)
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal method to push an option text to our scratch buffer.
|
||||
fn scratch_txt_opt(&self, txt: Option<impl AsRef<str>>) -> *const sys::cty::c_char {
|
||||
unsafe {
|
||||
let handle = &mut *self.buffer.get();
|
||||
handle.scratch_txt_opt(txt)
|
||||
}
|
||||
}
|
||||
|
||||
fn scratch_txt_two(
|
||||
&self,
|
||||
txt_0: impl AsRef<str>,
|
||||
txt_1: impl AsRef<str>,
|
||||
) -> (*const sys::cty::c_char, *const sys::cty::c_char) {
|
||||
unsafe {
|
||||
let handle = &mut *self.buffer.get();
|
||||
handle.scratch_txt_two(txt_0, txt_1)
|
||||
}
|
||||
}
|
||||
|
||||
fn scratch_txt_with_opt(
|
||||
&self,
|
||||
txt_0: impl AsRef<str>,
|
||||
txt_1: Option<impl AsRef<str>>,
|
||||
) -> (*const sys::cty::c_char, *const sys::cty::c_char) {
|
||||
unsafe {
|
||||
let handle = &mut *self.buffer.get();
|
||||
handle.scratch_txt_with_opt(txt_0, txt_1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an immutable reference to the inputs/outputs object
|
||||
#[doc(alias = "GetIO")]
|
||||
pub fn io(&self) -> &Io {
|
||||
unsafe { &*(sys::igGetIO() as *const Io) }
|
||||
}
|
||||
|
||||
/// Returns an immutable reference to the font atlas
|
||||
pub fn fonts(&self) -> FontAtlasRef<'_> {
|
||||
match self.font_atlas {
|
||||
Some(ref font_atlas) => FontAtlasRef::Shared(font_atlas),
|
||||
None => unsafe {
|
||||
let fonts = &*(self.io().fonts as *const FontAtlas);
|
||||
FontAtlasRef::Owned(fonts)
|
||||
},
|
||||
}
|
||||
}
|
||||
/// Returns a clone of the user interface style
|
||||
pub fn clone_style(&self) -> Style {
|
||||
*self.ctx.style()
|
||||
}
|
||||
/// Renders the frame and returns a reference to the resulting draw data
|
||||
#[doc(alias = "Render", alias = "GetDrawData")]
|
||||
pub fn render(self) -> &'ui DrawData {
|
||||
unsafe {
|
||||
sys::igRender();
|
||||
&*(sys::igGetDrawData() as *mut DrawData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for Ui<'a> {
|
||||
#[doc(alias = "EndFrame")]
|
||||
fn drop(&mut self) {
|
||||
if !thread::panicking() {
|
||||
unsafe {
|
||||
sys::igEndFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # Demo, debug, information
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Renders a demo window (previously called a test window), which demonstrates most
|
||||
/// Dear Imgui features.
|
||||
#[doc(alias = "ShowDemoWindow")]
|
||||
pub fn show_demo_window(&self, opened: &mut bool) {
|
||||
unsafe {
|
||||
sys::igShowDemoWindow(opened);
|
||||
}
|
||||
}
|
||||
/// Renders an about window.
|
||||
///
|
||||
/// Displays the Dear ImGui version/credits, and build/system information.
|
||||
#[doc(alias = "ShowAboutWindow")]
|
||||
pub fn show_about_window(&self, opened: &mut bool) {
|
||||
unsafe {
|
||||
sys::igShowAboutWindow(opened);
|
||||
}
|
||||
}
|
||||
/// Renders a metrics/debug window.
|
||||
///
|
||||
/// Displays Dear ImGui internals: draw commands (with individual draw calls and vertices),
|
||||
/// window list, basic internal state, etc.
|
||||
#[doc(alias = "ShowMetricsWindow")]
|
||||
pub fn show_metrics_window(&self, opened: &mut bool) {
|
||||
unsafe {
|
||||
sys::igShowMetricsWindow(opened);
|
||||
}
|
||||
}
|
||||
/// Renders a style editor block (not a window) for the given `Style` structure
|
||||
#[doc(alias = "ShowStyleEditor")]
|
||||
pub fn show_style_editor(&self, style: &mut Style) {
|
||||
unsafe {
|
||||
sys::igShowStyleEditor(style.raw_mut());
|
||||
}
|
||||
}
|
||||
/// Renders a style editor block (not a window) for the currently active style
|
||||
#[doc(alias = "ShowStyleEditor")]
|
||||
pub fn show_default_style_editor(&self) {
|
||||
unsafe { sys::igShowStyleEditor(ptr::null_mut()) };
|
||||
}
|
||||
/// Renders a basic help/info block (not a window)
|
||||
#[doc(alias = "ShowUserGuide")]
|
||||
pub fn show_user_guide(&self) {
|
||||
unsafe { sys::igShowUserGuide() };
|
||||
}
|
||||
}
|
||||
|
||||
/// Unique ID used by widgets
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Id<'a> {
|
||||
Int(i32),
|
||||
Str(&'a str),
|
||||
Ptr(*const c_void),
|
||||
}
|
||||
|
||||
impl From<i32> for Id<'static> {
|
||||
#[inline]
|
||||
fn from(i: i32) -> Self {
|
||||
Id::Int(i)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + AsRef<str>> From<&'a T> for Id<'a> {
|
||||
#[inline]
|
||||
fn from(s: &'a T) -> Self {
|
||||
Id::Str(s.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<*const T> for Id<'static> {
|
||||
#[inline]
|
||||
fn from(p: *const T) -> Self {
|
||||
Id::Ptr(p as *const c_void)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<*mut T> for Id<'static> {
|
||||
#[inline]
|
||||
fn from(p: *mut T) -> Self {
|
||||
Id::Ptr(p as *const T as *const c_void)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Id<'a> {
|
||||
// this is used in the tables-api and possibly elsewhere,
|
||||
// but not with just default features...
|
||||
#[allow(dead_code)]
|
||||
fn as_imgui_id(&self) -> sys::ImGuiID {
|
||||
unsafe {
|
||||
match self {
|
||||
Id::Ptr(p) => sys::igGetID_Ptr(*p),
|
||||
Id::Str(s) => {
|
||||
let s1 = s.as_ptr() as *const std::os::raw::c_char;
|
||||
let s2 = s1.add(s.len());
|
||||
sys::igGetID_StrStr(s1, s2)
|
||||
}
|
||||
Id::Int(i) => {
|
||||
let p = *i as *const std::os::raw::c_void;
|
||||
sys::igGetID_Ptr(p)
|
||||
} // Id::ImGuiID(n) => *n,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Default for Id<'a> {
|
||||
fn default() -> Self {
|
||||
Self::Int(0)
|
||||
}
|
||||
}
|
||||
|
||||
// Widgets: Input
|
||||
impl<'ui> Ui<'ui> {
|
||||
#[doc(alias = "InputText", alias = "InputTextWithHint")]
|
||||
pub fn input_text<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
buf: &'p mut String,
|
||||
) -> InputText<'ui, 'p, L> {
|
||||
InputText::new(self, label, buf)
|
||||
}
|
||||
#[doc(alias = "InputText", alias = "InputTextMultiline")]
|
||||
pub fn input_text_multiline<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
buf: &'p mut String,
|
||||
size: [f32; 2],
|
||||
) -> InputTextMultiline<'ui, 'p, L> {
|
||||
InputTextMultiline::new(self, label, buf, size)
|
||||
}
|
||||
#[doc(alias = "InputFloat2")]
|
||||
pub fn input_float<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut f32,
|
||||
) -> InputFloat<'ui, 'p, L> {
|
||||
InputFloat::new(self, label, value)
|
||||
}
|
||||
pub fn input_float2<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [f32; 2],
|
||||
) -> InputFloat2<'ui, 'p, L> {
|
||||
InputFloat2::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputFloat3")]
|
||||
pub fn input_float3<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [f32; 3],
|
||||
) -> InputFloat3<'ui, 'p, L> {
|
||||
InputFloat3::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputFloat4")]
|
||||
pub fn input_float4<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [f32; 4],
|
||||
) -> InputFloat4<'ui, 'p, L> {
|
||||
InputFloat4::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputInt")]
|
||||
pub fn input_int<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut i32,
|
||||
) -> InputInt<'ui, 'p, L> {
|
||||
InputInt::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputInt2")]
|
||||
pub fn input_int2<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [i32; 2],
|
||||
) -> InputInt2<'ui, 'p, L> {
|
||||
InputInt2::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputInt3")]
|
||||
pub fn input_int3<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [i32; 3],
|
||||
) -> InputInt3<'ui, 'p, L> {
|
||||
InputInt3::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputInt4")]
|
||||
pub fn input_int4<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [i32; 4],
|
||||
) -> InputInt4<'ui, 'p, L> {
|
||||
InputInt4::new(self, label, value)
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Tracks a layout tooltip that can be ended by calling `.end()` or by dropping.
|
||||
pub struct TooltipToken<'ui>;
|
||||
|
||||
/// Drops the layout tooltip manually. You can also just allow this token
|
||||
/// to drop on its own.
|
||||
drop { sys::igEndTooltip() }
|
||||
);
|
||||
|
||||
/// # Tooltips
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Construct a tooltip window that can have any kind of content.
|
||||
///
|
||||
/// Typically used with `Ui::is_item_hovered()` or some other conditional check.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use imgui::*;
|
||||
/// fn user_interface(ui: &Ui) {
|
||||
/// ui.text("Hover over me");
|
||||
/// if ui.is_item_hovered() {
|
||||
/// ui.tooltip(|| {
|
||||
/// ui.text_colored([1.0, 0.0, 0.0, 1.0], im_str!("I'm red!"));
|
||||
/// });
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "BeginTooltip", alias = "EndTootip")]
|
||||
pub fn tooltip<F: FnOnce()>(&self, f: F) {
|
||||
unsafe { sys::igBeginTooltip() };
|
||||
f();
|
||||
unsafe { sys::igEndTooltip() };
|
||||
}
|
||||
/// Construct a tooltip window that can have any kind of content.
|
||||
///
|
||||
/// Returns a `TooltipToken` that must be ended by calling `.end()`
|
||||
#[doc(alias = "BeginTooltip")]
|
||||
pub fn begin_tooltip(&self) -> TooltipToken<'_> {
|
||||
unsafe { sys::igBeginTooltip() };
|
||||
TooltipToken::new(self)
|
||||
}
|
||||
/// Construct a tooltip window with simple text content.
|
||||
///
|
||||
/// Typically used with `Ui::is_item_hovered()` or some other conditional check.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use imgui::*;
|
||||
/// fn user_interface(ui: &Ui) {
|
||||
/// ui.text("Hover over me");
|
||||
/// if ui.is_item_hovered() {
|
||||
/// ui.tooltip_text("I'm a tooltip!");
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "BeginTooltip", alias = "EndTootip")]
|
||||
pub fn tooltip_text<T: AsRef<str>>(&self, text: T) {
|
||||
self.tooltip(|| self.text(text));
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Starts a scope where interaction is disabled. Ends be calling `.end()` or when the token is dropped.
|
||||
pub struct DisabledToken<'ui>;
|
||||
|
||||
/// Drops the layout tooltip manually. You can also just allow this token
|
||||
/// to drop on its own.
|
||||
drop { sys::igEndDisabled() }
|
||||
);
|
||||
|
||||
/// # Disabling widgets
|
||||
///
|
||||
/// imgui can disable widgets so they don't react to mouse/keyboard
|
||||
/// inputs, and are displayed differently (currently dimmed by an
|
||||
/// amount set in [`Style::disabled_alpha`])
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Creates a scope where interactions are disabled.
|
||||
///
|
||||
/// Scope ends when returned token is dropped, or `.end()` is
|
||||
/// explicitly called
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use imgui::*;
|
||||
/// fn user_interface(ui: &Ui) {
|
||||
/// let disable_buttons = true;
|
||||
/// let _d = ui.begin_disabled(disable_buttons);
|
||||
/// ui.button(im_str!("Dangerous button"));
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
#[doc(alias = "BeginDisabled")]
|
||||
pub fn begin_disabled(&self, disabled: bool) -> DisabledToken<'_> {
|
||||
unsafe { sys::igBeginDisabled(disabled) };
|
||||
DisabledToken::new(self)
|
||||
}
|
||||
|
||||
/// Identical to [`Ui::begin_disabled`] but exists to allow avoiding a
|
||||
/// double-negative, for example `begin_enabled(enable_buttons)`
|
||||
/// instead of `begin_disabled(!enable_buttons)`)
|
||||
#[doc(alias = "BeginDisabled")]
|
||||
pub fn begin_enabled(&self, enabled: bool) -> DisabledToken<'_> {
|
||||
self.begin_disabled(!enabled)
|
||||
}
|
||||
|
||||
/// Helper to create a disabled section of widgets
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use imgui::*;
|
||||
/// fn user_interface(ui: &Ui) {
|
||||
/// let safe_mode = true;
|
||||
/// ui.disabled(safe_mode, || {
|
||||
/// ui.button(im_str!("Dangerous button"));
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "BeginDisabled", alias = "EndDisabled")]
|
||||
pub fn disabled<F: FnOnce()>(&self, disabled: bool, f: F) {
|
||||
unsafe { sys::igBeginDisabled(disabled) };
|
||||
f();
|
||||
unsafe { sys::igEndDisabled() };
|
||||
}
|
||||
|
||||
/// Same as [`Ui::disabled`] but with logic reversed. See
|
||||
/// [`Ui::begin_enabled`].
|
||||
#[doc(alias = "BeginDisabled", alias = "EndDisabled")]
|
||||
pub fn enabled<F: FnOnce()>(&self, enabled: bool, f: F) {
|
||||
unsafe { sys::igBeginDisabled(!enabled) };
|
||||
f();
|
||||
unsafe { sys::igEndDisabled() };
|
||||
}
|
||||
}
|
||||
|
||||
// Widgets: ListBox
|
||||
impl<'ui> Ui<'ui> {
|
||||
#[doc(alias = "ListBox")]
|
||||
pub fn list_box<'p, StringType: AsRef<str> + ?Sized>(
|
||||
&self,
|
||||
label: impl AsRef<str>,
|
||||
current_item: &mut i32,
|
||||
items: &'p [&'p StringType],
|
||||
height_in_items: i32,
|
||||
) -> bool {
|
||||
let (label_ptr, items_inner) = unsafe {
|
||||
let handle = &mut *self.buffer.get();
|
||||
|
||||
handle.refresh_buffer();
|
||||
let label_ptr = handle.push(label);
|
||||
|
||||
let items_inner: Vec<_> = items.iter().map(|&v| handle.push(v)).collect();
|
||||
|
||||
(label_ptr, items_inner)
|
||||
};
|
||||
|
||||
unsafe {
|
||||
sys::igListBox_Str_arr(
|
||||
label_ptr,
|
||||
current_item,
|
||||
items_inner.as_ptr() as *mut *const c_char,
|
||||
items_inner.len() as i32,
|
||||
height_in_items,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// written out for the future times...
|
||||
// #[doc(alias = "ListBox")]
|
||||
// pub fn list_box_const<'p, StringType: AsRef<str> + ?Sized, const N: usize>(
|
||||
// &self,
|
||||
// label: impl AsRef<str>,
|
||||
// current_item: &mut i32,
|
||||
// items: [&'p StringType; N],
|
||||
// height_in_items: i32,
|
||||
// ) -> bool {
|
||||
// let (label_ptr, items_inner) = unsafe {
|
||||
// let handle = &mut *self.buffer.get();
|
||||
|
||||
// handle.refresh_buffer();
|
||||
// let label_ptr = handle.push(label);
|
||||
|
||||
// let mut items_inner: [*const i8; N] = [std::ptr::null(); N];
|
||||
|
||||
// for (i, item) in items.iter().enumerate() {
|
||||
// items_inner[i] = handle.push(item);
|
||||
// }
|
||||
|
||||
// (label_ptr, items_inner)
|
||||
// };
|
||||
|
||||
// unsafe {
|
||||
// sys::igListBoxStr_arr(
|
||||
// label_ptr,
|
||||
// current_item,
|
||||
// items_inner.as_ptr() as *mut *const c_char,
|
||||
// items_inner.len() as i32,
|
||||
// height_in_items,
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
#[doc(alias = "PlotLines")]
|
||||
pub fn plot_lines<'p, Label: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: Label,
|
||||
values: &'p [f32],
|
||||
) -> PlotLines<'ui, 'p, Label> {
|
||||
PlotLines::new(self, label, values)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
#[doc(alias = "PlotHistogram")]
|
||||
pub fn plot_histogram<'p, Label: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: Label,
|
||||
values: &'p [f32],
|
||||
) -> PlotHistogram<'ui, 'p, Label> {
|
||||
PlotHistogram::new(self, label, values)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Calculate the size required for a given text string.
|
||||
///
|
||||
/// This is the same as [calc_text_size_with_opts](Self::calc_text_size_with_opts)
|
||||
/// with `hide_text_after_double_hash` set to false and `wrap_width` set to `-1.0`.
|
||||
#[doc(alias = "CalcTextSize")]
|
||||
pub fn calc_text_size<T: AsRef<str>>(&self, text: T) -> [f32; 2] {
|
||||
self.calc_text_size_with_opts(text, false, -1.0)
|
||||
}
|
||||
|
||||
/// Calculate the size required for a given text string.
|
||||
///
|
||||
/// hide_text_after_double_hash allows the user to insert comments into their text, using a double hash-tag prefix.
|
||||
/// This is a feature of imgui.
|
||||
///
|
||||
/// wrap_width allows you to request a width at which to wrap the text to a newline for the calculation.
|
||||
#[doc(alias = "CalcTextSize")]
|
||||
pub fn calc_text_size_with_opts<T: AsRef<str>>(
|
||||
&self,
|
||||
text: T,
|
||||
hide_text_after_double_hash: bool,
|
||||
wrap_width: f32,
|
||||
) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
let text = text.as_ref();
|
||||
|
||||
unsafe {
|
||||
let start = text.as_ptr();
|
||||
let end = start.add(text.len());
|
||||
|
||||
sys::igCalcTextSize(
|
||||
&mut out,
|
||||
start as *const c_char,
|
||||
end as *const c_char,
|
||||
hide_text_after_double_hash,
|
||||
wrap_width,
|
||||
)
|
||||
};
|
||||
out.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// # Draw list for custom drawing
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Get access to drawing API
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// fn custom_draw(ui: &Ui) {
|
||||
/// let draw_list = ui.get_window_draw_list();
|
||||
/// // Draw a line
|
||||
/// const WHITE: [f32; 3] = [1.0, 1.0, 1.0];
|
||||
/// draw_list.add_line([100.0, 100.0], [200.0, 200.0], WHITE).build();
|
||||
/// // Continue drawing ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This function will panic if several instances of [`DrawListMut`]
|
||||
/// coexist. Before a new instance is got, a previous instance should be
|
||||
/// dropped.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use imgui::*;
|
||||
/// fn custom_draw(ui: &Ui) {
|
||||
/// let draw_list = ui.get_window_draw_list();
|
||||
/// // Draw something...
|
||||
///
|
||||
/// // This second call will panic!
|
||||
/// let draw_list = ui.get_window_draw_list();
|
||||
/// }
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[doc(alias = "GetWindowDrawList")]
|
||||
pub fn get_window_draw_list(&'ui self) -> DrawListMut<'ui> {
|
||||
DrawListMut::window(self)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[doc(alias = "GetBackgroundDrawList")]
|
||||
pub fn get_background_draw_list(&'ui self) -> DrawListMut<'ui> {
|
||||
DrawListMut::background(self)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[doc(alias = "GetForegroundDrawList")]
|
||||
pub fn get_foreground_draw_list(&'ui self) -> DrawListMut<'ui> {
|
||||
DrawListMut::foreground(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Condition for applying a setting
|
||||
#[repr(i8)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Condition {
|
||||
/// Never apply the setting
|
||||
Never = -1,
|
||||
/// Always apply the setting
|
||||
Always = sys::ImGuiCond_Always as i8,
|
||||
/// Apply the setting once per runtime session (only the first call will succeed)
|
||||
Once = sys::ImGuiCond_Once as i8,
|
||||
/// Apply the setting if the object/window has no persistently saved data (no entry in .ini
|
||||
/// file)
|
||||
FirstUseEver = sys::ImGuiCond_FirstUseEver as i8,
|
||||
/// Apply the setting if the object/window is appearing after being hidden/inactive (or the
|
||||
/// first time)
|
||||
Appearing = sys::ImGuiCond_Appearing as i8,
|
||||
}
|
||||
|
||||
/// A cardinal direction
|
||||
#[repr(i32)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Direction {
|
||||
None = sys::ImGuiDir_None,
|
||||
Left = sys::ImGuiDir_Left,
|
||||
Right = sys::ImGuiDir_Right,
|
||||
Up = sys::ImGuiDir_Up,
|
||||
Down = sys::ImGuiDir_Down,
|
||||
}
|
||||
81
plugins/libimhex-rust/imgui-rs/src/list_clipper.rs
vendored
Normal file
81
plugins/libimhex-rust/imgui-rs/src/list_clipper.rs
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::thread;
|
||||
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
pub struct ListClipper {
|
||||
items_count: i32,
|
||||
items_height: f32,
|
||||
}
|
||||
|
||||
impl ListClipper {
|
||||
pub const fn new(items_count: i32) -> Self {
|
||||
ListClipper {
|
||||
items_count,
|
||||
items_height: -1.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn items_height(mut self, items_height: f32) -> Self {
|
||||
self.items_height = items_height;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> ListClipperToken<'ui> {
|
||||
let list_clipper = unsafe {
|
||||
let list_clipper = sys::ImGuiListClipper_ImGuiListClipper();
|
||||
sys::ImGuiListClipper_Begin(list_clipper, self.items_count, self.items_height);
|
||||
list_clipper
|
||||
};
|
||||
ListClipperToken::new(ui, list_clipper)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ListClipperToken<'ui> {
|
||||
list_clipper: *mut sys::ImGuiListClipper,
|
||||
_phantom: PhantomData<&'ui Ui<'ui>>,
|
||||
}
|
||||
|
||||
impl<'ui> ListClipperToken<'ui> {
|
||||
fn new(_: &Ui<'ui>, list_clipper: *mut sys::ImGuiListClipper) -> Self {
|
||||
Self {
|
||||
list_clipper,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn step(&mut self) -> bool {
|
||||
unsafe { sys::ImGuiListClipper_Step(self.list_clipper) }
|
||||
}
|
||||
|
||||
pub fn end(&mut self) {
|
||||
unsafe {
|
||||
sys::ImGuiListClipper_End(self.list_clipper);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_start(&self) -> i32 {
|
||||
unsafe { (*self.list_clipper).DisplayStart }
|
||||
}
|
||||
|
||||
pub fn display_end(&self) -> i32 {
|
||||
unsafe { (*self.list_clipper).DisplayEnd }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui> Drop for ListClipperToken<'ui> {
|
||||
fn drop(&mut self) {
|
||||
if !self.step() {
|
||||
unsafe {
|
||||
sys::ImGuiListClipper_destroy(self.list_clipper);
|
||||
};
|
||||
} else if !thread::panicking() {
|
||||
panic!(
|
||||
"Forgot to call End(), or to Step() until false? \
|
||||
This is the only token in the repository which users must call `.end()` or `.step()` \
|
||||
with. See https://github.com/imgui-rs/imgui-rs/issues/438"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user