Compare commits

...

272 Commits

Author SHA1 Message Date
WerWolv
d76e92933a feat: Added custom application delegate 2025-01-26 14:24:22 +01:00
WerWolv
403104dda1 fix: Properly scale unifont glyphs 2025-01-26 14:21:17 +01:00
WerWolv
8334fbb236 fix: Properly apply backing scaling to pixel perfect default font 2025-01-26 14:18:20 +01:00
WerWolv
0a0323ce5d git: Run CI on feature branches 2025-01-26 13:42:19 +01:00
WerWolv
726d36ba3d git: Fix creation of ARM64 DMG trying to enter wrong path 2025-01-26 11:26:04 +01:00
WerWolv
8bb1521963 git: Fix ARM64 .app path 2025-01-26 10:54:26 +01:00
WerWolv
9457c1f2b9 git: Install ImageMagick so create-dmg can make a pretty volume icon 2025-01-26 10:45:26 +01:00
WerWolv
2b24330f9f build: Updated ImHex icons in MSI installer 2025-01-26 10:40:53 +01:00
WerWolv
9329170e59 git: Ignore missing signature when building DMG 2025-01-26 10:32:37 +01:00
WerWolv
98f3de828a git: Add create-dmg to PATH 2025-01-26 10:27:09 +01:00
WerWolv
3f38f42259 git: Produce nicer looking DMG file for macOS 2025-01-26 10:19:05 +01:00
WerWolv
058a8cdc15 fix: Missing <cstdlib> include 2025-01-26 09:22:53 +01:00
WerWolv
d0c1213ea0 fix: Crash on systems where XDG_SESSION_TYPE isn't defined 2025-01-25 23:30:00 +01:00
WerWolv
30967bac6d fix: Modifier keys not working correctly on X11 2025-01-25 23:24:56 +01:00
WerWolv
09c9bcb046 fix: Pattern data filter not working correctly without a compare value 2025-01-25 23:17:03 +01:00
WerWolv
93f1f5d076 impr: Better font scaling with larger backing scale factors 2025-01-25 22:27:59 +01:00
WerWolv
93e5d62782 fix: Web build scaling 2025-01-25 20:12:21 +01:00
Bananchiki
4d7021ece1 lang: Added Russian translation (#1964)
<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->

### Description
This pull request introduces a complete Russian translation for ImHex,
ensuring that Russian-speaking users can navigate and utilize the
software in their native language. The translation covers all user
interface elements, menus, dialogs, and messages, providing a seamless
experience for Russian users.

### Testing
The translation has been thoroughly tested to ensure accuracy and
completeness. All translated text has been reviewed for grammatical
correctness and contextual appropriateness.

### Screenshots

![image](https://github.com/user-attachments/assets/455ca03d-0b33-45d2-9ed5-ddb404bd0728)

![image](https://github.com/user-attachments/assets/a7ebdb40-806f-43d9-ab36-deea730505c1)

![image](https://github.com/user-attachments/assets/29c5d21b-7443-4751-9129-e5fa054066d3)

Co-authored-by: Lemon4ksan <senya20151718@gmail.com>
2025-01-25 20:06:18 +01:00
WerWolv
f976988c75 impr: Try to detect backing scaling factor on the web build 2025-01-25 19:08:56 +01:00
WerWolv
1eee31fdbb fix: Debug mode only being enabled after everything has been initialized already 2025-01-25 16:54:16 +01:00
paxcut
048c483903 fix: Pattern Editor shortcuts not working correctly on different languages (#2085)
Fixes #2084 

Error in text editor prevented using shortcuts when language other than
English was chosen.

The code was mistakenly using localized name to test which window had
focus a execute the shortcut.

Fixed it by switching the name of the child window to the constant value
used to check the windows focused identity.
2025-01-25 16:34:27 +01:00
Wolf
b646ece14b impr: Refactor and restructure Event Manager (#2082)
### Problem description
This PR addresses issue #2013 that described a cluttered Event Manager.

This is a DX issue and should not impact the users whatsoever.

### Implementation description
The changes revolve around three main points:

1. the Event Manager (`event_manager.hpp`) was split into four
categories: GUI, Interaction, Lifecycle, and Provider, and two types:
Events, and Requests. This results in the following files:
    - `events_gui.hpp`
    - `events_interaction.hpp`
    - `events_lifecycle.hpp`
    - `events_provider.hpp`
    - `requests_gui.hpp`
    - `requests_interaction.hpp`
    - `requests_lifecycle.hpp`
    - `requests_provider.hpp`

2. Every event and request now has its own piece of documentation, with
a `@brief`, accompanied by a longer comment if needed, and gets its
`@param`s described.

3. The old `event_manager.hpp` import was removed and replaced by the
correct imports wherever needed, as to reduce spread of those files only
to where they are truly useful.

### Additional things
The commits have been split into (chrono-)logical steps:
- `feat`: split the Event Manager, and replace the imports
- `refactor`, `chore`: make various small changes to match the required
structure
- `docs`: add documentation for events and requests

Hopefully, this will help to review the PR.
*Note: Beware of very long rebuild times in between the commits, use
them sparingly! The Actions will ensure this PR builds anyways*

Closes #2013

---------

Signed-off-by: BioTheWolff <47079795+BioTheWolff@users.noreply.github.com>
Co-authored-by: Nik <werwolv98@gmail.com>
2025-01-25 15:32:07 +00:00
WerWolv
35e8acd69d impr: Only enable font config Apply button when setting has changed 2025-01-25 15:50:52 +01:00
WerWolv
de4135d1ad fix: ID collision with multiple items of the same name in the Accept Pattern popup 2025-01-25 15:47:09 +01:00
WerWolv
a44959ce1b feat: Added option to enable debug features in release builds 2025-01-25 15:38:57 +01:00
WerWolv
f4bad0053a fix: Linking errors in the web build 2025-01-25 15:24:44 +01:00
WerWolv
26af5987a5 fix: Properly check if distro info exists before printing it 2025-01-25 15:24:25 +01:00
WerWolv
9cf3250751 impr: Replace GitBook AI garbage with simple search API 2025-01-24 22:31:49 +01:00
WerWolv
acc77205bb fix: Image visualizer data processor nodes not working
Fixes #2081
2025-01-24 21:36:29 +01:00
WerWolv
a6b4f62d75 fix: Opening files in existing instance not working 2025-01-23 19:22:40 +01:00
WerWolv
69c5d553b5 fix: Disable postprocessing shaders in Web version 2025-01-22 19:55:17 +01:00
WerWolv
637cdd7084 git: Only generate attestation on main repo 2025-01-22 19:19:19 +01:00
WerWolv
8978e193db impr: Better OS-specific handling of system exceptions 2025-01-21 23:28:22 +01:00
WerWolv
242b100aa3 fix: Properly detect Windows 10 2025-01-20 21:45:53 +01:00
WerWolv
3a888d48df fix: ID collision with color inline visualizer 2025-01-20 21:25:00 +01:00
WerWolv
721de39dbb impr: Make icon context menu use MenuItemEx for its icons 2025-01-20 21:24:49 +01:00
WerWolv
07e29f2030 feat: Added support for OpenGL post processing shaders 2025-01-20 21:24:25 +01:00
WerWolv
c117d9b3e5 fix: Crash when changing DPI 2025-01-19 23:07:53 +01:00
WerWolv
16eae89151 fix: Save/Save As toolbar items being missing by default 2025-01-19 21:49:34 +01:00
WerWolv
95cb6d8ee6 patterns: Updated pattern language 2025-01-19 19:23:48 +01:00
WerWolv
af27c09204 fix: I guess we can still not use std::views::enumerate 2025-01-19 17:54:18 +01:00
WerWolv
5e3532267c fix: Missing glfw include 2025-01-19 17:52:32 +01:00
WerWolv
7c0331df65 impr: Hide window on macOS when close button is pressed 2025-01-19 17:04:31 +01:00
WerWolv
04ab87cd8e patterns: Updated pattern language 2025-01-19 14:42:02 +01:00
WerWolv
91f5e84250 impr: Don't insert a new line at the end of settings pages 2025-01-19 10:56:00 +01:00
WerWolv
b1edd95ebc impr: Shortcut code cleanup 2025-01-19 10:55:27 +01:00
WerWolv
758738da5c fix: Default font not being the default font 2025-01-19 10:34:54 +01:00
WerWolv
41c8be275b fix: Assert when selecting selectable text 2025-01-19 00:26:26 +01:00
WerWolv
117eb1e2a7 feat: Added more granular font settings
Fixes #1260
2025-01-18 23:34:43 +01:00
WerWolv
3129d6e8fd impr: Simplified custom font selection 2025-01-18 19:03:55 +01:00
WerWolv
2ba7db184b build: Fix favicon transparency for ImHex Web 2025-01-18 17:47:36 +01:00
WerWolv
2cb0df4080 build: Properly optimize web build 2025-01-18 16:53:11 +01:00
WerWolv
3adc2c44e6 fix: Font customization not unlocking correctly 2025-01-18 16:05:11 +01:00
WerWolv
6d3ff64894 fix: ImHex using a lot of CPU 2025-01-18 14:57:06 +01:00
WerWolv
cf84ad6196 fix: Added back old constructor for Widgets::DropDown 2025-01-18 14:56:53 +01:00
WerWolv
6259190ad9 impr: Make localization fall back to english if it doesn't exist 2025-01-18 14:40:10 +01:00
WerWolv
181be1a58e fix: Missing paste behaviour option translations 2025-01-18 14:36:31 +01:00
WerWolv
771e191f28 fix: Windows icon not being transparent anymore 2025-01-18 14:11:49 +01:00
WerWolv
d4d6893eb3 git: Make sure PORTABLE flag is created correctly 2025-01-18 13:58:20 +01:00
WerWolv
9e75562662 build: Fix RPM icon path 2025-01-18 13:45:57 +01:00
WerWolv
2b3168163b git: Extract PDBs for for portable version properly 2025-01-18 13:45:32 +01:00
WerWolv
252c06eb12 build: Extract PDBs from build files 2025-01-18 13:26:12 +01:00
WerWolv
2a51d8169a build: Move icon to correct location 2025-01-18 13:18:33 +01:00
WerWolv
7405c4b411 build: Updated disassembler library 2025-01-18 13:06:31 +01:00
WerWolv
309ae7b619 build: Fixed disassembler library git messup 2025-01-18 12:38:20 +01:00
WerWolv
64ef56a0df git: Fixed Windows PDB extraction process 2025-01-18 12:04:46 +01:00
WerWolv
fbfe7b0d25 impr: Unlock frame rate for the first few seconds after startup 2025-01-18 11:58:49 +01:00
WerWolv
8c7e1a3b2d impr: Replace icon with Papyrus icon.
Special thanks to @varlesh and @morganist
See https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/issues/3909
2025-01-18 11:55:17 +01:00
WerWolv
bf249cdafe build: Updated disassembler library 2025-01-18 11:07:28 +01:00
WerWolv
59ba6f50cc build: Disable install targets of libfmt to fix Windows WIX installer 2025-01-18 11:03:51 +01:00
WerWolv
8d6e7c7d44 fix: Decompressor compile errors 2025-01-18 10:28:20 +01:00
WerWolv
52934ae166 feat: Make decompress functions return number of read bytes 2025-01-18 10:14:47 +01:00
WerWolv
56c4f2aa47 fix: ID collision with multiple banners on screen 2025-01-17 23:12:09 +01:00
WerWolv
a1d8cbd7ba fix: Properly update window position during resize 2025-01-17 23:11:53 +01:00
Nik
63a219a32b build: Added ARM64 AppImage build (#2073) 2025-01-17 22:55:41 +01:00
WerWolv
14fb256a6a build: Updated dependencies 2025-01-17 21:09:56 +01:00
WerWolv
95df7a23c3 build: Add new SDK files to Fedora package 2025-01-17 20:41:49 +01:00
WerWolv
bb17690cf5 build: Fix cv2pdb extraction errors 2025-01-17 19:56:25 +01:00
WerWolv
a943b02e43 build: Make sure unzip is installed on the CI 2025-01-17 19:50:41 +01:00
WerWolv
199f78347f build: Move PDB extraction to CI 2025-01-17 19:44:33 +01:00
WerWolv
d3d9a42d57 build: Added library plugin files to SDK 2025-01-17 19:32:52 +01:00
WerWolv
1fa45a8c84 fix: Replace bookmark comment Text Editor with multi-line text input
Closes #2056, Closes #2055
2025-01-17 17:28:13 +01:00
WerWolv
0b6316ea23 fix: Added back deleted variable to make web build work again 2025-01-17 17:26:46 +01:00
WerWolv
466a843263 build: Fix backwards compat with older cmake versions 2025-01-17 13:01:40 +01:00
WerWolv
b6ade8b101 fix: Shortcuts not working in detached windows 2025-01-17 12:39:55 +01:00
WerWolv
ff66b97e90 build: Get rid of some cmake warnings 2025-01-17 12:39:39 +01:00
WerWolv
c604ec8fb9 patterns: Updated pattern language 2025-01-16 21:23:22 +01:00
WerWolv
7564651dd5 patterns: Updated pattern language 2025-01-16 19:52:45 +01:00
WerWolv
cad17ddefd fix: Banners being misplaced on macOS 2025-01-16 19:27:22 +01:00
WerWolv
25d2f209e5 patterns: Updated pattern language 2025-01-16 19:15:39 +01:00
WerWolv
8d660c3ffe fix: Missing <numbers> include 2025-01-16 17:37:51 +01:00
WerWolv
209055d0b0 impr: Show a banner about degraded performance in debug mode 2025-01-16 17:09:17 +01:00
WerWolv
599b55965a impr: Improve the shadow of banners 2025-01-16 17:09:04 +01:00
WerWolv
69a9af5322 patterns: Added error pattern to pattern drawer 2025-01-16 17:08:49 +01:00
WerWolv
0303cd0ad0 patterns: Updated pattern language 2025-01-16 17:08:23 +01:00
WerWolv
8eb7e9fb05 fix: ID collision in provider data information section 2025-01-15 20:34:25 +01:00
WerWolv
6a1de5fc4e build: Updated ImGui to v1.91.7 2025-01-15 19:52:24 +01:00
WerWolv
a4af55cb66 build: Rename imgui_custom to imgui_backend 2025-01-15 19:52:19 +01:00
paxcut
1e17422f5e fix: Pattern Editor Find and Replace history (#2064)
The previous implementation seems to have been broken by Imgui updates. 

There is also some improvement in focus handling and also a bug in
replace where the last match was not being replaced has been fixed.

Fixed also slowdown in large files when only one char was typed by not
searching until enter has been pressed.

Added key repetitions for enter and arrows to be able to handle large
number of matches and fixed some formatting problems.
2025-01-15 19:40:12 +01:00
paxcut
8abaafab79 fix: Crash in 3D Visualizer, improved error messages (#2062)
The recently added data checks allowed invalid sized vertex arrays to be
used as if they were valid making ImHex crash.

Moved all the error messages into localization strings for translation.
2025-01-15 19:38:38 +01:00
WerWolv
71e1465524 fix: Image visualizer node trying to create texture in non-main thread 2025-01-15 19:34:58 +01:00
WerWolv
3d2ea3753b fix: Missing <clocale> include 2025-01-15 19:31:33 +01:00
Nik
88530eff8b git: Updated screenshots in readme 2025-01-15 18:31:41 +01:00
WerWolv
df3decf71b build: Updated libwolv 2025-01-15 18:08:45 +01:00
WerWolv
565ee4cb2d fix: Banner positions with multi-viewports enabled 2025-01-15 18:08:05 +01:00
WerWolv
40fc325ba9 fix: Disable bogus Keypad to function key conversions on macOS 2025-01-15 17:59:57 +01:00
WerWolv
6aca16102d impr: Move up the right column on the welcome screen to avoid a scrollbar at default size 2025-01-15 17:54:35 +01:00
WerWolv
cb11b57ab1 feat: Added banners, replace some modals with them 2025-01-15 17:54:07 +01:00
WerWolv
d504937d50 fix: Empty regions in Intel Hex and Motorola SREC files not being displayed correctly 2025-01-14 23:54:07 +01:00
WerWolv
6bfdb7ca4e fix: Make sure provider switch buttons and close button don't overlap 2025-01-14 22:10:58 +01:00
WerWolv
e1637824c6 impr: Make strings in the data information view selectable and copyable 2025-01-14 22:05:29 +01:00
WerWolv
e36f2f2bcb fix: Replace "data processor" text with "data inspector" for the custom data inspector row hint 2025-01-14 17:51:26 +01:00
WerWolv
1a54e08f11 fix: Remove constexpr from functions that really aren't constexpr 2025-01-14 17:50:48 +01:00
WerWolv
ecc86ee429 fix: ImNodes not being deinitialized correctly 2025-01-14 17:50:29 +01:00
WerWolv
185a593bc2 fix: AllowWhileTyping shortcuts only working while typing 2025-01-14 17:50:06 +01:00
WerWolv
4a916ebb89 feat: Added New File option to the GNOME launcher and a --new cli option 2025-01-14 17:49:48 +01:00
WerWolv
1c305ca762 fix: Icons still following custom font size when using default font 2025-01-13 22:34:30 +01:00
WerWolv
17fff56fa0 impr: Make sure Windows title icon is scaled correctly 2025-01-13 22:31:24 +01:00
WerWolv
ec1b1c2b7d impr: More constexpr 2025-01-13 22:31:06 +01:00
WerWolv
7bae22f56f fix: Font selector still saying "Custom Font Path" 2025-01-13 22:20:53 +01:00
WerWolv
21e5eeef16 impr: Reduce default font size slightly, adjust element sizes on welcome screen 2025-01-13 22:17:14 +01:00
WerWolv
bf5eea80f6 impr: Make font size setting use points instead of pixels 2025-01-13 22:04:55 +01:00
WerWolv
9f9a6d9827 impr: Move Jetbrains mono into regular font selector, allow it to be scaled 2025-01-13 22:04:44 +01:00
WerWolv
ae622e6d75 git: Merge WebAssembly build into main build artifacts script, add to releases 2025-01-12 23:08:09 +01:00
WerWolv
68fbff631f git: Fix github pages artifact name 2025-01-12 22:50:39 +01:00
WerWolv
6cdce75095 git: Upload artifact for ImHex Web build 2025-01-12 22:03:50 +01:00
WerWolv
f699e76c56 build: Fix comment causing issues with docker 2025-01-11 21:41:14 +01:00
WerWolv
a729329cd4 impr: Added missing [[nodiscard]]s 2025-01-11 21:40:42 +01:00
WerWolv
d5020ce9bb impr: Rename Jump To option to Follow Selection to avoid confusion with Go To 2025-01-11 21:40:26 +01:00
WerWolv
126868c251 fix: Hang when filtering for a large number of items in the pattern data view 2025-01-11 17:22:53 +01:00
WerWolv
b206e9fc95 fix: Copy-paste error with "Extend selection left" shortcut name 2025-01-11 16:42:00 +01:00
WerWolv
4b6ff68464 git: Fixed CI permissions 2025-01-11 16:28:29 +01:00
WerWolv
b23a0febb5 git: Added build provenance attestation for most artifacts 2025-01-11 16:17:27 +01:00
WerWolv
05ad547341 git: Use zstd to compress .deb builds 2025-01-11 15:57:42 +01:00
paxcut
f10af882a7 fix: Text Editor find option jumping to the wrong location (#2060)
After successfully finding matches and setting the cursor to them, the
screen would jump to the original window location upon closing the
window.

The error was caused by the wrong assumption that the scroll location
should be restored when window is closed. Instead, the right amount of
scrolling needs to be calculated to account for the window no longer
covering part of the text editor. Unused variable was discarded.

Another unrelated error is that the history of search names cannot be
accessed which will be addressed at a later PR.
2025-01-09 18:39:00 +01:00
WerWolv
98f32ebcad impr: Made interactive help api easier to use 2025-01-09 18:34:39 +01:00
WerWolv
e2c302836f feat: Added support for scanning binaries for UTF-8 strings 2025-01-09 18:33:45 +01:00
WerWolv
f1d9642cf6 impr: Better color picker widgets in the settings 2025-01-07 21:46:26 +01:00
WerWolv
5c58e5b545 fix: Selection highlight color setting not working
Fixes #2059
2025-01-07 18:09:56 +01:00
WerWolv
803cb335e1 feat: Added interface accent colors 2025-01-07 00:06:52 +01:00
WerWolv
ae4dde8255 impr: Unlock frame rate in more cases to make the UI feel more responsive 2025-01-06 20:34:00 +01:00
WerWolv
cb34f68b1b patterns: Updated pattern language 2025-01-06 20:15:21 +01:00
WerWolv
96ef983cfb fix: ASCII column not getting highlighted anymore 2025-01-06 20:14:27 +01:00
WerWolv
d8c3d67dfe build: Disable romfs compression in web build 2025-01-05 21:25:28 +01:00
WerWolv
5de5153663 impr: Simplify hex editor class API 2025-01-05 21:24:13 +01:00
WerWolv
1e747b6831 patterns: Updated pattern language 2025-01-05 19:18:46 +01:00
WerWolv
fbe9d16073 build: Updated libromfs 2025-01-05 17:52:04 +01:00
WerWolv
d02c0073a0 build: Ignore pdb copy file errors 2025-01-05 15:27:54 +01:00
WerWolv
1090b9879c build: Make pdb copy operation happen at install time 2025-01-05 15:20:03 +01:00
WerWolv
5a6af976cd build: Rename output pdb file if necessary 2025-01-05 15:14:25 +01:00
WerWolv
55e39a5d30 build: Fix dwarf stripping logic 2025-01-05 15:00:45 +01:00
WerWolv
c9b1ddfb59 build: Updated libromfs 2025-01-05 14:56:16 +01:00
WerWolv
f7dd696ffc build: Silence stupid brew errors 2025-01-05 14:51:03 +01:00
WerWolv
70f210ac5d build: Updated libromfs 2025-01-05 14:37:39 +01:00
WerWolv
cad1c11f8b build: Updated dependencies 2025-01-05 14:17:54 +01:00
WerWolv
f7fa305e82 build: Generate pdb file for libpl, significantly reduce binary size 2025-01-05 12:06:32 +01:00
WerWolv
f96c51e854 impr: Added shortcut for Copy as -> Custom Encoding 2025-01-05 11:12:56 +01:00
WerWolv
c19705d3e5 git: Try to silence brew error messages again 2025-01-05 10:42:29 +01:00
WerWolv
1190511994 impr: Cleanup frame rate unlocking code 2025-01-04 23:43:10 +01:00
WerWolv
69ee7ef63c build: Updated libwolv 2025-01-04 23:42:56 +01:00
WerWolv
fc95e5a9a8 impr: Unlock frame rate when scrolling or focusing 2025-01-04 22:00:26 +01:00
WerWolv
6ecc495d43 feat: Added visibility toggle to hide bookmark highlighting 2025-01-04 21:40:18 +01:00
WerWolv
6e861001cf impr: Allow all highlights to overlap each other 2025-01-04 21:40:03 +01:00
WerWolv
c56af08c7e impr: Allow highlights of multiple overlapping bookmarks to render 2025-01-04 20:46:56 +01:00
WerWolv
e68abefe48 impr: Use info icon for more help hovers 2025-01-04 19:21:22 +01:00
WerWolv
fd0635cb82 fix: Hex editor right click menu not working on macOS 2025-01-04 19:08:37 +01:00
WerWolv
baa3cfb354 fix: User folders being added twice 2025-01-04 18:30:57 +01:00
iTrooz
aea9bab853 build: Make MacOS arm64 build use clang 19 (#2050) 2025-01-04 18:10:48 +01:00
WerWolv
48de609f53 impr: Added telemetry about whether ImHex runs on a corporate machine 2025-01-04 16:11:35 +01:00
WerWolv
71f4f87288 impr: Make sure init tasks always get executed 2025-01-04 16:11:05 +01:00
WerWolv
48b202c56b patterns: Updated pattern language 2025-01-04 15:38:20 +01:00
Nik
d975019a7b impr: Revamp frame rate limiting system to make ImHex feel less laggy in certain cases (#2049) 2025-01-04 15:35:19 +01:00
Nik
6009b5013b feat: Let ImHex use the native menu bar on macOS (#2048) 2025-01-04 15:35:06 +01:00
WerWolv
24979d7fbd impr: Other Providers -> Other Data Sources 2025-01-04 14:06:03 +01:00
WerWolv
b4bf42e377 fix: Unit test build error due to changed Provider::getTypeName() signature 2025-01-04 13:57:48 +01:00
WerWolv
f94819351a impr: Make maximum in-memory file size setting easier to use. Bump value to 512MiB 2025-01-04 13:56:20 +01:00
WerWolv
8da69c11d9 impr: Remove the word "Provider" from places where it doesn't fit 2025-01-04 13:28:35 +01:00
WerWolv
635a825095 fix: Signed/Unsigned comparison error 2025-01-04 13:03:38 +01:00
WerWolv
bbffdbf56f feat: Allow #pragma magic to index from the end of the data with negative addresses
Closes #2047
2025-01-04 12:49:14 +01:00
WerWolv
1c30533d19 fix: Off-by-one when calculating hashes of selected regions
Fixes #2046
2025-01-04 00:15:35 +01:00
WerWolv
dcd80fe6ad impr: Properly scale window on wayland 2025-01-03 15:09:06 +01:00
WerWolv
525ab8d945 fix: Settings not being saved correctly anymore 2025-01-03 14:07:09 +01:00
WerWolv
d8fb3f526a fix: Shortcut migration not working correctly in some cases
Fixes #2045
2025-01-03 10:16:22 +01:00
WerWolv
a55df1d111 fix: Exception being thrown when custom disassembler folders didn't exist 2025-01-03 00:15:52 +01:00
WerWolv
2cf32ba38d fix: Default smooth font not being scaled correctly 2025-01-03 00:15:28 +01:00
AlexGuo1998
c82907153e fix: Set LZMA decompressor memory limit to 1GiB (#2044)
<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->

### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->

See #2033 (`hex::dec::lzma_decompress` reports an error when
decompressing a small buffer).

### Implementation description
<!-- Explain what you did to correct the problem -->

Set the LZMA decompressor memory limit to 1GiB fixed. Print a warning
when exceeded, and abort with returning `false`.

### Screenshots
<!-- If your change is visual, take a screenshot showing it. Ideally,
make before/after sceenshots -->

Normal result when decompressing a small buffer


![image](https://github.com/user-attachments/assets/5b9e6b07-464e-41f6-bdc7-f5b1cd351069)

Warning message when `memlimit` is exceeded: (Set to 64B here for a
demo)
> W: lzma_decompress memory usage 1114168 bytes would exceed the limit
(64 bytes), aborting


![image](https://github.com/user-attachments/assets/04abf3ef-1d29-4846-bb41-214695c7d09c)

### Additional things
<!-- Anything else you would like to say -->

Is the warning wording OK? I'm not a native English speaker so please
change it if you want to.
2025-01-02 08:42:28 +00:00
WerWolv
165403da67 fix: ImHex freezing on AMD GPUs when resizing
Fixes #1842
2025-01-01 20:39:12 +01:00
WerWolv
0e4d94946e fix: Disable recent files on web build since they can't work there 2025-01-01 17:08:31 +01:00
WerWolv
9f9c5abf35 impr: Prevent window from being moved while hovering over items on macOS 2025-01-01 16:45:11 +01:00
WerWolv
6a3b10111f feat: Highlight main menu item when using a shortcut 2025-01-01 16:19:38 +01:00
WerWolv
0a55f4bf83 patterns: Updated pattern language
Fixes #2042
2025-01-01 11:36:04 +01:00
WerWolv
493d66d991 fix: Crash when using hex editor when provider == nullptr 2024-12-31 21:30:05 +01:00
WerWolv
268b495a29 fix: Make capstone use little endian by default 2024-12-31 21:17:19 +01:00
WerWolv
180f4926f8 impr: Make disassembly view contain data per-provider 2024-12-31 21:16:27 +01:00
WerWolv
c853349b78 impr: Force reset window decoration to expected value after exiting full screen mode 2024-12-31 21:04:09 +01:00
WerWolv
ee555e0da9 fix: Make sure WM_NCCALCSIZE never tries to sleep a negative amount of time
#1842
2024-12-31 18:06:31 +01:00
WerWolv
3dec4cc698 fix: Signed/Unsigned integer compare 2024-12-31 17:21:37 +01:00
WerWolv
d7b2b94cec impr: Reduce jittering when changing the number of hex columns 2024-12-31 17:04:32 +01:00
WerWolv
c9e88586aa feat: Added option to fit hex columns to screen width 2024-12-31 11:35:09 +01:00
WerWolv
1d641504b1 fix: Format string issues 2024-12-31 10:01:01 +01:00
WerWolv
655e068b9b impr: Added changed data information to diff view table 2024-12-31 00:47:32 +01:00
WerWolv
67a9f314cc impr: Added icons to more context menus 2024-12-31 00:45:47 +01:00
WerWolv
ff2b58e8a3 fix: Copy paste errors 2024-12-30 23:58:34 +01:00
WerWolv
a1482cb40e fix: Tooltips not being hidden when disabling hex editor highlights 2024-12-30 23:45:48 +01:00
WerWolv
89111059f9 feat: Added setting to disable hex editor highlights entirely 2024-12-30 23:24:59 +01:00
WerWolv
0ae823716a feat: Added a preview to the Edit -> Copy as options
Closes #2026
2024-12-30 23:16:11 +01:00
WerWolv
dab3f722e8 feat: Added "Jump to address" option to data inspector row context menu 2024-12-30 22:32:06 +01:00
WerWolv
0dc1af0747 feat: Added option to change radix of numbers in hex editor view 2024-12-30 21:00:43 +01:00
WerWolv
021206e052 impr: Added icons to pattern editor context menu 2024-12-30 12:18:55 +01:00
WerWolv
cb09cf3734 feat: Added context menu and next/previous buttons to the data inspector 2024-12-30 12:07:21 +01:00
WerWolv
f0525d6463 fix: Building issues with the web build 2024-12-30 10:10:38 +01:00
WerWolv
e22424ffa4 fix: Settings not being saved correctly on the web version 2024-12-29 23:53:23 +01:00
WerWolv
6e666c64e8 patterns: Updated pattern language 2024-12-29 22:42:32 +01:00
WerWolv
5f5f6ac539 feat: Added option to move selection back to hex editor footer
Closes #2024
2024-12-29 21:08:08 +01:00
WerWolv
3024c79f4f impr: Allow the favorite column in the pattern data view to be hidden 2024-12-29 20:38:51 +01:00
WerWolv
ba96d86dc2 impr: Properly align favorite icons inside of the buttons in the pattern drawer 2024-12-29 20:38:25 +01:00
WerWolv
40ec7195d1 patterns: Updated pattern language 2024-12-29 15:20:57 +01:00
WerWolv
f10dfa0c20 patterns: Updated pattern language 2024-12-29 14:40:51 +01:00
WerWolv
6a5473f6fe impr: Moved Windows DPI awareness to manifest file, added detached console allocation
Closes #1543
2024-12-28 23:47:42 +01:00
WerWolv
f79de6fbe8 fix: Web build not starting fully anymore 2024-12-28 22:48:06 +01:00
Nik
ec4ee3132b git: Added note about launching assertion failures when launching the AppImage (#2038) 2024-12-28 22:31:34 +01:00
WerWolv
1298f2b688 impr: Refactor previous commits to work with other environments too 2024-12-28 21:37:45 +01:00
WerWolv
534a2f1d28 impr: Apply framebuffer scaling to SVGs as well 2024-12-28 20:52:49 +01:00
WerWolv
c8e95cf3c3 impr: Keep default font at whole-integer sizes 2024-12-28 20:46:26 +01:00
WerWolv
c4918a963c fix: Default font not being scaled on macOS 2024-12-28 20:45:12 +01:00
WerWolv
bf6f738d2e impr: Make text look super pretty on macOS finally 2024-12-28 20:42:05 +01:00
Nik
1605904eb1 git: Updated more runners to Ubuntu 24.04 2024-12-28 16:49:33 +01:00
Nik
138517f116 git: Updated system requirements and compile info in the readme 2024-12-28 16:48:32 +01:00
WerWolv
d4a4cb2e80 fix: Crash when providing invalid version string to semantic version class
Fixes #2036
2024-12-28 15:59:13 +01:00
WerWolv
9a9dc328e3 build: Switch to custom lunasvg repo to allow offline builds 2024-12-28 13:39:07 +01:00
WerWolv
50eea0a4f1 impr: Replace Firacode with JetbrainsMono font 2024-12-28 12:43:34 +01:00
WerWolv
528a8b5b46 fix: Exception being thrown when getting version parts from invalid version 2024-12-28 11:45:05 +01:00
WerWolv
0db0bc53fa revert: Make pattern editor scroll bar look more like all other scrollbars 2024-12-28 00:39:10 +01:00
WerWolv
0297c267e9 impr: Display "ImHex" in title bar when null provider is open 2024-12-27 23:56:14 +01:00
WerWolv
5af85f24f6 impr: Allow command palette to be closed by clicking on the menu bar 2024-12-27 23:53:55 +01:00
WerWolv
5110a7578e fix: Rendering issues with text editor in bookmark view 2024-12-27 23:36:21 +01:00
WerWolv
5af28670f0 fix: Ctrl sometimes getting stuck when pressing ALT GR and other keys at the same time
#2019
2024-12-27 23:15:20 +01:00
WerWolv
efa2b781dd impr: Better create hash popup size 2024-12-27 23:14:39 +01:00
WerWolv
979f151181 fix: Don't show library plugins in --plugins subcommand 2024-12-27 20:06:17 +01:00
WerWolv
6f125f18c3 impr: Make pattern editor scroll bar look more like all other scrollbars 2024-12-27 20:01:00 +01:00
WerWolv
edba7051f0 impr: Make interactive tutorials select windows when they're highlighted 2024-12-27 19:41:45 +01:00
WerWolv
fa1ae8d746 fix: Tutorial highlights not working anymore correctly 2024-12-27 18:28:22 +01:00
WerWolv
a476617432 build: Fix remaining build issues 2024-12-27 00:02:37 +01:00
WerWolv
ffac13bfef disasm: Updated disassembler library 2024-12-26 23:28:38 +01:00
WerWolv
f877bf21ba fix: Warning on macOS about wrong format argument 2024-12-26 23:01:19 +01:00
WerWolv
4bc4882b1f disasm: Updated disassembler library 2024-12-26 23:00:59 +01:00
WerWolv
084c17dc26 fix: Missing endian setting in ARM64 disassembler 2024-12-26 22:39:57 +01:00
WerWolv
26c39d6822 fix: ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback -> ImGui_ImplGlfw_InstallEmscriptenCallbacks 2024-12-26 20:19:55 +01:00
WerWolv
aefc173227 fix: Wrong --reset-settings subcommand description 2024-12-26 20:05:07 +01:00
WerWolv
bf44a1cce6 feat: Added initial support for custom disassemblers 2024-12-26 20:04:45 +01:00
WerWolv
a76c6c653d impr: Refactor disassembler system to make it more modular 2024-12-26 18:41:34 +01:00
WerWolv
f11205bba7 build: Updated more dependencies 2024-12-26 14:41:43 +01:00
WerWolv
72d9c5019c build: Updated dependencies 2024-12-26 14:30:52 +01:00
WerWolv
58d66e3e97 fix: Added migration routine to fix shortcuts 2024-12-26 14:01:54 +01:00
WerWolv
43c88a2fab feat: Added system to handle version migrations 2024-12-26 14:01:46 +01:00
paxcut
9ce64ec6e1 fix: Pattern Editor console scroll jumping. (#2029)
Some issues related to the padding added to scroll past the end for
console that has padding added.
Added a shortcut to scroll editors one pixel at a time.
Fixed whole lines always drawn at the top even if scroll value is chosen
so that only a portion of the top line is visible. This caused errors in
horizontal scrolling.
Fixed Ctrl-F Ctrl-G and Ctrl-H messing the editor display. 
Fixed the end of the line could not be clicked with mouse 
Fixed line numbers and their lines could be displayed at different
heights.
Made numbers that represented lines floats instead of integers to allow
partial line display.
2024-12-25 18:51:58 +01:00
WerWolv
c749d6a7dc fix: Disable ImGui assert that causes random crashes on resize 2024-12-25 18:49:50 +01:00
WerWolv
f3e6d35c98 build: Updated ImGui glfw backend 2024-12-25 18:44:43 +01:00
WerWolv
0be539b8a5 feat: Added option to copy data as escaped string
#2026
2024-12-25 16:45:34 +01:00
WerWolv
0454a369e5 fix: Crashes when disassembling data
Fixes #2025
2024-12-25 16:36:53 +01:00
WerWolv
010025cbfa fix: Wrong localStorage key for achievements 2024-12-25 16:21:38 +01:00
WerWolv
61cae0a9f8 fix: Missing emscripten include 2024-12-25 16:19:50 +01:00
WerWolv
9e83d9e68c fix: Disable browser ctrl + S in web build 2024-12-25 16:17:51 +01:00
WerWolv
248acd5e26 fix: Properly save achievements in web version 2024-12-25 16:17:33 +01:00
WerWolv
42c1f5601a fix: Saving files in web version not working correctly 2024-12-25 15:57:54 +01:00
WerWolv
9c1a673047 impr: Force update all installed content store items after an update 2024-12-25 14:29:41 +01:00
WerWolv
99b90f90ac fix: Unused variable in wasm build 2024-12-25 13:03:55 +01:00
WerWolv
6ead8d8b49 fix: Certain shortcuts not being captured by ImHex Web 2024-12-25 12:36:06 +01:00
WerWolv
9b12232e9f revert: Broken fix for cursor not being set at end of line 2024-12-25 01:41:50 +01:00
WerWolv
c1ed1baaad fix: Shortcuts not working correctly in Web build 2024-12-25 01:34:11 +01:00
WerWolv
ab34312089 fix: Clicking past end of line in text editor putting cursor before last character 2024-12-25 01:33:41 +01:00
WerWolv
a25d92fbb7 build: Bumped version to 1.37.0.WIP 2024-12-25 01:33:36 +01:00
284 changed files with 11415 additions and 4351 deletions

View File

@@ -6,6 +6,7 @@ on:
- 'master'
- 'releases/**'
- 'tests/**'
- 'feature/**'
pull_request:
workflow_dispatch:
@@ -18,11 +19,18 @@ jobs:
win:
runs-on: windows-2022
name: 🪟 Windows MINGW64
defaults:
run:
shell: msys2 {0}
env:
CCACHE_DIR: "${{ github.workspace }}/.ccache"
permissions:
id-token: write
attestations: write
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
@@ -81,11 +89,64 @@ jobs:
run: |
cd build
ninja install
- name: 🪲 Create PDBs for MSI
run: |
cd build
mkdir cv2pdb
cd cv2pdb
wget https://github.com/rainers/cv2pdb/releases/download/v0.52/cv2pdb-0.52.zip
unzip cv2pdb-0.52.zip
cd ..
cv2pdb/cv2pdb.exe imhex.exe
cv2pdb/cv2pdb.exe imhex-gui.exe
cv2pdb/cv2pdb.exe libimhex.dll
cv2pdb/cv2pdb.exe libpl.dll
for plugin in plugins/*.hexplug; do
cv2pdb/cv2pdb.exe $plugin
done
rm -rf cv2pdb
- name: 📦 Bundle MSI
run: |
cd build
cpack
mv ImHex-*.msi ../imhex-${{ env.IMHEX_VERSION }}-Windows-x86_64.msi
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
- name: 🪲 Create PDBs for ZIP
run: |
cd build/install
mkdir cv2pdb
cd cv2pdb
wget https://github.com/rainers/cv2pdb/releases/download/v0.52/cv2pdb-0.52.zip
unzip cv2pdb-0.52.zip
cd ..
cv2pdb/cv2pdb.exe imhex.exe
cv2pdb/cv2pdb.exe imhex-gui.exe
cv2pdb/cv2pdb.exe libimhex.dll
cv2pdb/cv2pdb.exe libpl.dll
for plugin in plugins/*.hexplug; do
cv2pdb/cv2pdb.exe $plugin
done
rm -rf cv2pdb
- name: 🗝️ Generate build provenance attestations
uses: actions/attest-build-provenance@v2
if: github.event.pull_request.head.repo.full_name == github.repository
with:
subject-path: |
imhex-*.msi
- name: ⬆️ Upload Windows Installer
uses: actions/upload-artifact@v4
with:
@@ -122,12 +183,16 @@ jobs:
win-plugin-template-test:
runs-on: windows-2022
name: 🧪 Plugin Template Test
defaults:
run:
shell: msys2 {0}
needs: win
env:
IMHEX_SDK_PATH: "${{ github.workspace }}/out/sdk"
steps:
- name: 🧰 Checkout ImHex
uses: actions/checkout@v4
@@ -173,9 +238,13 @@ jobs:
ninja
# MacOS build
macos:
macos-x86:
runs-on: macos-13
permissions:
id-token: write
attestations: write
strategy:
fail-fast: false
matrix:
@@ -205,10 +274,13 @@ jobs:
max-size: 1G
- name: ⬇️ Install dependencies
env:
# Make brew not display useless errors
HOMEBREW_TESTS: 1
run: |
brew reinstall python --quiet || true
brew link --overwrite --quiet python || true
brew bundle --no-lock --quiet --file dist/Brewfile || true
brew link --overwrite --quiet python 2>/dev/null || true
brew bundle --no-lock --quiet --file dist/macOS/Brewfile || true
rm -rf /usr/local/Cellar/capstone
- name: ⬇️ Install classic glfw
@@ -299,19 +371,20 @@ jobs:
- name: 📦 Create DMG
run: |
set -x
mkdir bundle
mv build/install/ImHex.app bundle
cd bundle
ln -s /Applications Applications
cd ..
for i in $(seq 1 10); do
if hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{ env.IMHEX_VERSION }}-macOS${{ matrix.suffix }}-x86_64.dmg; then
echo "Created dmg after ${i} attempts"
break
fi
sleep 10
done
brew install imagemagick
git clone https://github.com/sindresorhus/create-dmg
cd create-dmg
npm i && npm -g i
cd ../build/install
create-dmg ImHex.app || true
mv *.dmg ../../imhex-${{ env.IMHEX_VERSION }}-macOS${{ matrix.suffix }}-x86_64.dmg
- name: 🗝️ Generate build provenance attestations
uses: actions/attest-build-provenance@v2
if: github.event.pull_request.head.repo.full_name == github.repository
with:
subject-path: |
./*.dmg
- name: ⬆️ Upload DMG
uses: actions/upload-artifact@v4
@@ -320,11 +393,13 @@ jobs:
name: macOS DMG${{ matrix.suffix }} x86_64
path: ./*.dmg
macos-arm64-build:
macos-arm64:
runs-on: ubuntu-24.04
name: 🍎 macOS 13 arm64
outputs:
IMHEX_VERSION: ${{ steps.build.outputs.IMHEX_VERSION }}
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
@@ -367,9 +442,15 @@ jobs:
macos-arm64-package:
runs-on: macos-13
name: 🍎 macOS 13 arm64 Packaging
needs: macos-arm64-build
needs: macos-arm64
env:
IMHEX_VERSION: ${{ needs.macos-arm64-build.outputs.IMHEX_VERSION }}
permissions:
id-token: write
attestations: write
steps:
- name: ⬇️ Download artifact
uses: actions/download-artifact@v4
@@ -404,19 +485,20 @@ jobs:
- name: 📦 Create DMG
run: |
set -x
mkdir bundle
mv out/ImHex.app bundle
cd bundle
ln -s /Applications Applications
cd ..
for i in $(seq 1 10); do
if hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{ env.IMHEX_VERSION }}-macOS-arm64.dmg; then
echo "Created dmg after ${i} attempts"
break
fi
sleep 10
done
brew install imagemagick
git clone https://github.com/sindresorhus/create-dmg
cd create-dmg
npm i && npm -g i
cd ../out
create-dmg ImHex.app || true
mv *.dmg ../imhex-${{ env.IMHEX_VERSION }}-macOS${{ matrix.suffix }}-arm64.dmg
- name: 🗝️ Generate build provenance attestations
uses: actions/attest-build-provenance@v2
if: github.event.pull_request.head.repo.full_name == github.repository
with:
subject-path: |
./*.dmg
- name: ⬆️ Upload DMG
uses: actions/upload-artifact@v4
@@ -441,6 +523,10 @@ jobs:
image: "ubuntu:${{ matrix.release_num }}"
options: --privileged
permissions:
id-token: write
attestations: write
steps:
- name: ⬇️ Install setup dependencies
run: apt update && apt install -y git curl
@@ -498,9 +584,16 @@ jobs:
- name: 📦 Bundle DEB
run: |
cp -r build/DEBIAN build/DebDir
dpkg-deb -Zgzip --build build/DebDir
dpkg-deb -Zzstd --build build/DebDir
mv build/DebDir.deb imhex-${{ env.IMHEX_VERSION }}-Ubuntu-${{ matrix.release_num }}-x86_64.deb
- name: 🗝️ Generate build provenance attestations
uses: actions/attest-build-provenance@v2
if: github.event.pull_request.head.repo.full_name == github.repository
with:
subject-path: |
./*.deb
- name: ⬆️ Upload DEB
uses: actions/upload-artifact@v4
with:
@@ -510,8 +603,26 @@ jobs:
# AppImage build
appimage:
runs-on: ubuntu-24.04
name: ⬇️ AppImage
strategy:
fail-fast: false
matrix:
include:
- architecture: "x86_64"
architecture_package: "amd64"
architecture_appimage_builder: "x86_64"
image: ubuntu-24.04
- architecture: "arm64"
architecture_package: "arm64"
architecture_appimage_builder: "aarch64"
image: ubuntu-24.04-arm
runs-on: ${{ matrix.image }}
name: ⬇️ AppImage ${{ matrix.architecture }}
permissions:
id-token: write
attestations: write
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
@@ -533,22 +644,31 @@ jobs:
- name: 🛠️ Build using docker
run: |
docker buildx build . -f dist/appimage/Dockerfile --progress=plain --build-arg "BUILD_TYPE=$BUILD_TYPE" \
--build-arg "GIT_COMMIT_HASH=$GITHUB_SHA" --build-arg "GIT_BRANCH=${GITHUB_REF##*/}" --output out
docker buildx build . -f dist/AppImage/Dockerfile --progress=plain --build-arg "BUILD_TYPE=$BUILD_TYPE" \
--build-arg "GIT_COMMIT_HASH=$GITHUB_SHA" --build-arg "GIT_BRANCH=${GITHUB_REF##*/}" \
--build-arg "ARCHITECTURE_PACKAGE=${{ matrix.architecture_package }}" --build-arg "ARCHITECTURE_FILE_NAME=${{ matrix.architecture }}" --build-arg "ARCHITECTURE_APPIMAGE_BUILDER=${{ matrix.architecture_appimage_builder }}" \
--output out
- name: 🗝️ Generate build provenance attestations
uses: actions/attest-build-provenance@v2
if: github.event.pull_request.head.repo.full_name == github.repository
with:
subject-path: |
out/*.AppImage
out/*.AppImage.zsync
- name: ⬆️ Upload AppImage
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: Linux AppImage x86_64
name: Linux AppImage ${{ matrix.architecture }}
path: 'out/*.AppImage'
- name: ⬆️ Upload AppImage zsync
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: Linux AppImage zsync x86_64
name: Linux AppImage zsync ${{ matrix.architecture }}
path: 'out/*.AppImage.zsync'
# ArchLinux build
@@ -559,6 +679,10 @@ jobs:
container:
image: archlinux:base-devel
permissions:
id-token: write
attestations: write
steps:
- name: ⬇️ Update all packages
run: |
@@ -642,6 +766,13 @@ jobs:
rm *imhex-bin-debug* # rm debug package which is created for some reason
mv *.pkg.tar.zst imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst
- name: 🗝️ Generate build provenance attestations
uses: actions/attest-build-provenance@v2
if: github.event.pull_request.head.repo.full_name == github.repository
with:
subject-path: |
build/imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
uses: actions/upload-artifact@v4
with:
@@ -680,6 +811,10 @@ jobs:
image: "almalinux:9"
options: --privileged --pid=host --security-opt apparmor=unconfined
permissions:
id-token: write
attestations: write
steps:
# This, together with the `--pid=host --security-opt apparmor=unconfined` docker options is required to allow
# fedpkg to work inside a Docker container running on Ubuntu again.
@@ -775,6 +910,13 @@ jobs:
mv $GITHUB_WORKSPACE/results_imhex/${{ env.IMHEX_VERSION }}/*/imhex-${{ env.IMHEX_VERSION }}-0.*.x86_64.rpm \
$GITHUB_WORKSPACE/imhex-${{ env.IMHEX_VERSION }}-${{ matrix.name }}-${{ matrix.release_num }}-x86_64.rpm
- name: 🗝️ Generate build provenance attestations
uses: actions/attest-build-provenance@v2
if: github.event.pull_request.head.repo.full_name == github.repository
with:
subject-path: |
imhex-${{ env.IMHEX_VERSION }}-${{ matrix.name }}-${{ matrix.release_num }}-x86_64.rpm
- name: ⬆️ Upload RPM
uses: actions/upload-artifact@v4
with:
@@ -782,3 +924,85 @@ jobs:
name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64
path: |
imhex-${{ env.IMHEX_VERSION }}-${{ matrix.name }}-${{ matrix.release_num }}-x86_64.rpm
webassembly-build:
runs-on: ubuntu-24.04
name: 🌍 Web
permissions:
pages: write
id-token: write
actions: write
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: 📁 Restore docker /cache
uses: actions/cache@v4
with:
path: cache
key: web-cache-${{ hashFiles('**/CMakeLists.txt') }}
- name: 🐳 Inject /cache into docker
uses: reproducible-containers/buildkit-cache-dance@v2
with:
cache-source: cache
cache-target: /cache
- name: 🛠️ Build using docker
run: |
docker buildx build . -f dist/web/Dockerfile --progress=plain --build-arg 'JOBS=4' --output out --target raw
- name: 🔨 Fix permissions
run: |
chmod -c -R +rX "out/"
- name: ⬆️ Upload artifacts
uses: actions/upload-pages-artifact@v3
with:
path: out/
- name: 🔨 Copy necessary files
run: |
cp dist/web/serve.py out/start_imhex_web.py
- name: ⬆️ Upload package
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: ImHex Web
path: out/*
# See https://github.com/actions/cache/issues/342#issuecomment-1711054115
- name: 🗑️ Delete old cache
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: |
gh extension install actions/gh-actions-cache || true
gh actions-cache delete "build-web-cache" --confirm || true
webassembly-deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
permissions:
pages: write
id-token: write
actions: write
name: 📃 Deploy to GitHub Pages
runs-on: ubuntu-24.04
if: ${{ github.ref == 'refs/heads/master' && github.event.repository.fork == false }}
needs: webassembly-build
steps:
- name: 🌍 Deploy WebAssembly Build to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
- name: 🗑️ Delete artifact
uses: geekyeggo/delete-artifact@v5
with:
name: github-pages

View File

@@ -1,79 +0,0 @@
name: Build for the web
on:
push:
branches:
- 'master'
- 'releases/**'
- 'tests/**'
pull_request:
workflow_dispatch:
env:
BUILD_TYPE: Release
permissions:
pages: write
id-token: write
actions: write
jobs:
build:
runs-on: ubuntu-24.04
name: 🌍 WebAssembly
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: 📁 Restore docker /cache
uses: actions/cache@v4
with:
path: cache
key: web-cache-${{ hashFiles('**/CMakeLists.txt') }}
- name: 🐳 Inject /cache into docker
uses: reproducible-containers/buildkit-cache-dance@v2
with:
cache-source: cache
cache-target: /cache
- name: 🛠️ Build using docker
run: |
docker buildx build . -f dist/web/Dockerfile --progress=plain --build-arg 'JOBS=4' --output out --target raw
- name: 🔨 Fix permissions
run: |
chmod -c -R +rX "out/"
- name: ⬆️ Upload artifacts
uses: actions/upload-pages-artifact@v3
with:
path: out/
# See https://github.com/actions/cache/issues/342#issuecomment-1711054115
- name: 🗑️ Delete old cache
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: |
gh extension install actions/gh-actions-cache || true
gh actions-cache delete "build-web-cache" --confirm || true
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
name: 📃 Deploy to GitHub Pages
runs-on: ubuntu-24.04
if: ${{ github.ref == 'refs/heads/master' && github.event.repository.fork == false }}
needs: build
steps:
- name: 🌍 Deploy
id: deployment
uses: actions/deploy-pages@v4

View File

@@ -63,7 +63,7 @@ jobs:
token: ${{ secrets.RELEASE_TOKEN }}
release-upload-artifacts:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
name: Release Upload Artifacts
steps:
@@ -117,6 +117,7 @@ jobs:
run: |
mv "Windows Portable x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-x86_64.zip
mv "Windows Portable NoGPU x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-NoGPU-x86_64.zip
mv "ImHex Web.zip" imhex-${{ env.IMHEX_VERSION }}-web.zip
- name: ⬆️ Upload everything to release
uses: softprops/action-gh-release@4634c16e79c963813287e889244c50009e7f0981

View File

@@ -6,7 +6,7 @@ on:
jobs:
close-issues:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
permissions:
issues: write
pull-requests: write

View File

@@ -6,6 +6,7 @@ on:
- 'master'
- 'releases/**'
- 'tests/**'
- 'feature/**'
pull_request:
branches:
- 'master'

7
.gitmodules vendored
View File

@@ -28,7 +28,7 @@
ignore = dirty
[submodule "lib/third_party/lunasvg"]
path = lib/third_party/lunasvg
url = https://github.com/sammycage/lunasvg
url = https://github.com/WerWolv/lunasvg
ignore = dirty
[submodule "lib/external/libromfs"]
@@ -43,4 +43,7 @@
[submodule "lib/third_party/HashLibPlus"]
path = lib/third_party/HashLibPlus
url = https://github.com/WerWolv/HashLibPlus
url = https://github.com/WerWolv/HashLibPlus
[submodule "lib/external/disassembler"]
path = lib/external/disassembler
url = https://github.com/WerWolv/Disassembler

View File

@@ -81,7 +81,6 @@ if (IMHEX_ENABLE_UNIT_TESTS)
endif ()
# Configure more resources that will be added to the install package
generatePDBs()
generateSDKDirectory()
# Handle package generation

View File

@@ -27,6 +27,11 @@ chmod +x imhex-*.AppImage
./imhex-*.AppImage
```
If you're experiencing glib / libgtk assertion failures, you might need to setup your `XDG_DATA_DIRS` env var correctly. In this case, run the following command before executing the AppImage. (See issue [ImHex/#2038](https://github.com/WerWolv/ImHex/issues/2038))
```bash
export XDG_DATA_DIRS="/usr/local/share:/usr/share"
```
#### Flatpak
To install the Flatpak, make sure you have the Flathub repository added to your system. Then simply run the following command:

View File

@@ -38,8 +38,8 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
</p>
## Screenshots
![Hex editor, patterns and data information](https://github.com/WerWolv/ImHex/assets/10835354/4f358238-2d27-41aa-9015-a2c6cc3708cf)
![Bookmarks, disassembler and data processor](https://github.com/WerWolv/ImHex/assets/10835354/183bc2cc-2439-4ded-b4c5-b140e19fc92f)
![Hex editor, patterns and data information](https://github.com/user-attachments/assets/902a7c4c-410d-490f-999e-14c856fec027)
![Bookmarks, data information, find view and data processor](https://github.com/user-attachments/assets/58eefa1f-31c9-4bb8-a1c1-8cdd8ddbd29f)
<details>
<summary><strong>More Screenshots</strong></summary>
@@ -328,12 +328,12 @@ To use ImHex, the following minimal system requirements need to be met.
- RHEL/AlmaLinux
- Arch Linux
- Basically any other distro will work as well when compiling ImHex from sources.
- **CPU**: x86_64 (64 Bit)
- **CPU**: Officially supported are x86_64 and ARM64, though any Little Endian 64 bit CPU should work.
- **GPU**: OpenGL 3.0 or higher
- Integrated Intel HD iGPUs are supported, however certain drivers are known to cause various graphical artifacts, especially on Windows. Use at your own risk.
- In case you don't have a GPU available, there are software rendered releases available for Windows and macOS
- **RAM**: 256MB, more may be required for more complicated analysis
- **Storage**: 150MB
- **RAM**: ~150MiB, more is required for more complex analysis
- **Storage**: 150MiB
## Installing
@@ -342,8 +342,10 @@ Information on how to install ImHex can be found in the [Install](/INSTALL.md) g
## Compiling
To compile ImHex on any platform, GCC (or Clang) is required with a version that supports C++23 or higher.
On macOS, Clang is also required to compile some ObjC code.
All releases are being built using latest available GCC.
Windows and Linux releases are being built using latest available GCC.
MacOS releases are being built using latest available LLVM Clang.
Important to note is, the MSVC and AppleClang compilers are both **NOT** supported since they're both generally severely outdated and lack features GCC and LLVM Clang have.
> [!NOTE]
> Many dependencies are bundled into the repository using submodules so make sure to clone it using the `--recurse-submodules` option.

View File

@@ -1 +1 @@
1.36.0
1.37.0.WIP

View File

@@ -1,3 +1,17 @@
# Some libraries we use set the BUILD_SHARED_LIBS variable to ON, which causes CMake to
# display a warning about options being set using set() instead of option().
# Explicitly set the policy to NEW to suppress the warning.
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW)
if (POLICY CMP0177)
set(CMAKE_POLICY_DEFAULT_CMP0177 OLD)
cmake_policy(SET CMP0177 OLD)
endif()
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "Disable deprecated warnings" FORCE)
include(FetchContent)
if(IMHEX_STRIP_RELEASE)
@@ -226,7 +240,7 @@ macro(createPackage)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/imhex.mime.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/mime/packages RENAME imhex.xml)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.svg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.svg)
downloadImHexPatternsFiles("./share/imhex")
# install AppStream file
@@ -370,15 +384,6 @@ macro(configureCMake)
message(WARNING "LTO is not supported: ${output_error}")
endif ()
endif ()
# Some libraries we use set the BUILD_SHARED_LIBS variable to ON, which causes CMake to
# display a warning about options being set using set() instead of option().
# Explicitly set the policy to NEW to suppress the warning.
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW)
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "Disable deprecated warnings" FORCE)
endmacro()
function(configureProject)
@@ -649,6 +654,7 @@ macro(addBundledLibraries)
set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "")
if(NOT USE_SYSTEM_FMT)
set(FMT_INSTALL OFF CACHE BOOL "Disable install targets for libfmt" FORCE)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/fmt EXCLUDE_FROM_ALL)
set(FMT_LIBRARIES fmt::fmt-header-only)
else()
@@ -728,6 +734,7 @@ macro(addBundledLibraries)
endif()
add_subdirectory(${EXTERNAL_LIBS_FOLDER}/pattern_language EXCLUDE_FROM_ALL)
add_subdirectory(${EXTERNAL_LIBS_FOLDER}/disassembler EXCLUDE_FROM_ALL)
if (LIBPL_SHARED_LIBRARY)
install(
@@ -784,59 +791,6 @@ function(enableUnityBuild TARGET)
endif ()
endfunction()
function(generatePDBs)
if (NOT IMHEX_GENERATE_PDBS)
return()
endif ()
if (NOT WIN32 OR CMAKE_BUILD_TYPE STREQUAL "Debug")
return()
endif ()
include(FetchContent)
FetchContent_Declare(
cv2pdb
URL "https://github.com/rainers/cv2pdb/releases/download/v0.52/cv2pdb-0.52.zip"
DOWNLOAD_EXTRACT_TIMESTAMP ON
)
FetchContent_Populate(cv2pdb)
set(PDBS_TO_GENERATE main main-forwarder libimhex ${PLUGINS})
foreach (PDB ${PDBS_TO_GENERATE})
if (PDB STREQUAL "main")
set(GENERATED_PDB imhex)
elseif (PDB STREQUAL "main-forwarder")
set(GENERATED_PDB imhex-gui)
elseif (PDB STREQUAL "libimhex")
set(GENERATED_PDB libimhex)
else ()
set(GENERATED_PDB plugins/${PDB})
endif ()
if (IMHEX_REPLACE_DWARF_WITH_PDB)
set(PDB_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${GENERATED_PDB})
else ()
set(PDB_OUTPUT_PATH)
endif()
add_custom_target(${PDB}_pdb DEPENDS ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb)
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMAND
(
${CMAKE_COMMAND} -E remove -f ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb &&
${cv2pdb_SOURCE_DIR}/cv2pdb64.exe $<TARGET_FILE:${PDB}> ${PDB_OUTPUT_PATH} &&
${CMAKE_COMMAND} -E remove -f ${CMAKE_BINARY_DIR}/${GENERATED_PDB}
) || (exit 0)
COMMAND_EXPAND_LISTS)
install(FILES ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb DESTINATION ".")
add_dependencies(imhex_all ${PDB}_pdb)
endforeach ()
endfunction()
function(generateSDKDirectory)
if (WIN32)
set(SDK_PATH "./sdk")
@@ -865,6 +819,12 @@ function(generateSDKDirectory)
install(FILES ${CMAKE_SOURCE_DIR}/cmake/build_helpers.cmake DESTINATION "${SDK_PATH}/cmake")
install(DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/sdk/ DESTINATION "${SDK_PATH}")
install(TARGETS libimhex ARCHIVE DESTINATION "${SDK_PATH}/lib")
install(DIRECTORY ${CMAKE_SOURCE_DIR}/plugins/ui DESTINATION "${SDK_PATH}/lib" PATTERN "**/source/*" EXCLUDE)
install(TARGETS ui ARCHIVE DESTINATION "${SDK_PATH}/lib")
install(DIRECTORY ${CMAKE_SOURCE_DIR}/plugins/fonts DESTINATION "${SDK_PATH}/lib" PATTERN "**/source/*" EXCLUDE)
install(TARGETS fonts ARCHIVE DESTINATION "${SDK_PATH}/lib")
endfunction()
function(addIncludesFromLibrary target library)

View File

@@ -11,32 +11,23 @@ AppDir:
exec_args: $@
apt:
arch:
- amd64
- "{{ARCHITECTURE_PACKAGE}}"
allow_unauthenticated: true
sources:
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular main restricted
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates main restricted
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular universe
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates universe
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular multiverse
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates multiverse
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-backports main restricted
universe multiverse
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security main restricted
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security universe
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security multiverse
- sourceline: 'deb [arch=amd64] http://us.archive.ubuntu.com/ubuntu/ oracular main restricted universe multiverse'
- sourceline: 'deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ oracular main restricted universe multiverse'
include:
- librsvg2-common
- libbz2-1.0:amd64
- libcap2:amd64
- libdbus-1-3:amd64
- libfontconfig1:amd64
- libgpg-error0:amd64
- liblzma5:amd64
- libnss-mdns:amd64
- libpcre3:amd64
- libselinux1:amd64
- libtinfo6:amd64
- libbz2-1.0
- libcap2
- libdbus-1-3
- libfontconfig1
- libgpg-error0
- liblzma5
- libnss-mdns
- libpcre3
- libselinux1
- libtinfo6
files:
include:
- /lib/x86_64-linux-gnu/libLLVM-13.so.1
@@ -133,6 +124,6 @@ AppDir:
- usr/share/doc/*/NEWS.*
- usr/share/doc/*/TODO.*
AppImage:
arch: x86_64
update-information: gh-releases-zsync|WerWolv|ImHex|latest|imhex-*-x86_64.AppImage.zsync
file_name: imhex-{{VERSION}}-x86_64.AppImage
arch: "{{ARCHITECTURE_APPIMAGE_BUILDER}}"
update-information: gh-releases-zsync|WerWolv|ImHex|latest|imhex-*-{{ARCHITECTURE_FILE_NAME}}.AppImage.zsync
file_name: imhex-{{VERSION}}-{{ARCHITECTURE_FILE_NAME}}.AppImage

View File

@@ -30,8 +30,14 @@ ARG LTO=ON
ARG BUILD_TYPE=RelWithDebInfo
ARG GIT_COMMIT_HASH
ARG GIT_BRANCH
ARG ARCHITECTURE_PACKAGE
ARG ARCHITECTURE_FILE_NAME
ARG ARCHITECTURE_APPIMAGE_BUILDER
WORKDIR /build
SHELL ["bash", "-c"] # Ubuntu sh doesnt support string substitution
# Ubuntu sh doesnt support string substitution
SHELL ["bash", "-c"]
RUN <<EOF
# Prepare ImHex build
set -xe
@@ -73,7 +79,10 @@ pip3 install git+https://github.com/AppImageCrafters/appimage-builder@f38699e
# Package ImHex as AppImage
export VERSION=$(cat /imhex/VERSION)
appimage-builder --recipe /imhex/dist/AppImageBuilder.yml
export ARCHITECTURE_PACKAGE=${ARCHITECTURE_PACKAGE}
export ARCHITECTURE_FILE_NAME=${ARCHITECTURE_FILE_NAME}
export ARCHITECTURE_APPIMAGE_BUILDER=${ARCHITECTURE_APPIMAGE_BUILDER}
appimage-builder --recipe /imhex/dist/AppImage/AppImageBuilder.yml
EOF
FROM scratch

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env sh
pacman -S --needed --noconfirm pactoys
pacman -S --needed --noconfirm pactoys unzip
pacboy -S --needed --noconfirm \
gcc:p \
lld:p \

6
dist/imhex.desktop vendored
View File

@@ -1,4 +1,5 @@
[Desktop Entry]
Version=1.0
Name=ImHex
Comment=ImHex Hex Editor
GenericName=Hex Editor
@@ -10,3 +11,8 @@ Categories=Development;IDE;
StartupWMClass=imhex
Keywords=static-analysis;reverse-engineering;disassembler;disassembly;hacking;forensics;hex-editor;cybersecurity;security;binary-analysis;
MimeType=application/vnd.imhex.proj;
Actions=NewFile;
[Desktop Action NewFile]
Exec=imhex --new
Name=Create New File

View File

@@ -1,5 +1,5 @@
# This base image is also known as "crosscompile". See arm64.crosscompile.Dockerfile
FROM ghcr.io/itrooz/macos-crosscompile:clang17-nosdk as build
FROM ghcr.io/itrooz/macos-crosscompile:clang19-nosdk as build
ENV MACOSX_DEPLOYMENT_TARGET 13.0

View File

@@ -1,4 +1,4 @@
# This image is is provided for reference, but a (probably more up to date) image should be available at https://github.com/iTrooz/macos-crosscompile
# This image is provided for reference, but a (probably more up to date) image should be available at https://github.com/iTrooz/macos-crosscompile
FROM ubuntu:22.04
ENV PATH $PATH:/osxcross/target/bin

4
dist/rpm/imhex.spec vendored
View File

@@ -123,9 +123,11 @@ cp -a lib/third_party/xdgpp/LICENSE %{buildroot
%doc README.md
%{_bindir}/imhex
%{_bindir}/imhex-updater
%{_datadir}/pixmaps/%{name}.png
%{_datadir}/pixmaps/%{name}.svg
%{_datadir}/applications/%{name}.desktop
%{_datadir}/mime/packages/%{name}.xml
%{_libdir}/libimhex.so*
%{_libdir}/%{name}/
%{_libdir}/*.hexpluglib
/usr/lib/debug/%{_libdir}/*.debug
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml

11
dist/web/Dockerfile vendored
View File

@@ -1,4 +1,4 @@
FROM emscripten/emsdk:3.1.51 as build
FROM emscripten/emsdk:3.1.51 AS build
# Used to invalidate layer cache but not mount cache
# See https://github.com/moby/moby/issues/41715#issuecomment-733976493
@@ -27,7 +27,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
' >> /emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
EOF
ENV VCPKG_DEFAULT_BINARY_CACHE /cache/vcpkg
ENV VCPKG_DEFAULT_BINARY_CACHE=/cache/vcpkg
RUN --mount=type=cache,target=/cache <<EOF
# Install dependencies with vcpkg
set -xe
@@ -45,7 +45,7 @@ EOF
# Build ImHex
ARG JOBS=4
ENV CCACHE_DIR /cache/ccache
ENV CCACHE_DIR=/cache/ccache
RUN mkdir /build
WORKDIR /build
@@ -67,6 +67,7 @@ cmake /imhex
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake \
-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake \
-DLIBROMFS_COMPRESS_RESOURCES=OFF \
-DCMAKE_BUILD_TYPE=Release
ninja -j $JOBS
@@ -79,7 +80,7 @@ EOF
# See https://stackoverflow.com/questions/41701849/cannot-modify-accept-encoding-with-fetch https://github.com/AnthumChris/fetch-progress-indicators/issues/13
RUN du -b /build/imhex.wasm | cut -f1 > imhex.wasm.size
FROM scratch as raw
FROM scratch AS raw
COPY --from=build [ \
# ImHex \
"/build/imhex.wasm", \
@@ -93,7 +94,7 @@ COPY --from=build [ \
"/build/wasm-config.js", \
"/build/enable-threads.js", \
"/build/favicon.ico", \
"/build/icon.png", \
"/build/icon.svg", \
"/build/manifest.json", \
"/build/robots.txt", \
"/build/sitemap.xml", \

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

11
dist/web/source/icon.svg vendored Normal file
View File

@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" version="1">
<rect style="opacity:0.2" width="55" height="10" x="5" y="-60" rx="1.41" transform="rotate(90)"/>
<rect style="fill:#2b50a1" width="55" height="10" x="4" y="-60" rx="1.41" transform="rotate(90)"/>
<rect style="fill:#2b50a1" width="55" height="10" x="4" y="-14" rx="1.41" transform="rotate(90)"/>
<rect style="fill:#2b50a1" width="55" height="10" x="4" y="-33" rx="1.41" transform="rotate(90)"/>
<path style="opacity:0.2" d="M 5.3808594,5 C 4.6158118,5 4,5.6158118 4,6.3808594 V 13.619141 C 4,14.384188 4.6158118,15 5.3808594,15 H 31.619141 C 32.384188,15 33,14.384188 33,13.619141 V 6.3808594 C 33,5.6158118 32.384188,5 31.619141,5 Z M 40.400391,5 C 39.624791,5 39,5.6247906 39,6.4003906 V 13.599609 C 39,14.375209 39.624791,15 40.400391,15 H 58.599609 C 59.375209,15 60,14.375209 60,13.599609 V 6.4003906 C 60,5.6247906 59.375209,5 58.599609,5 Z M 5.3808594,50 C 4.6158118,50 4,50.615812 4,51.380859 v 7.238282 C 4,59.384188 4.6158118,60 5.3808594,60 H 31.619141 C 32.384188,60 33,59.384188 33,58.619141 V 51.380859 C 33,50.615812 32.384188,50 31.619141,50 Z"/>
<rect style="fill:#3a6be0" width="29" height="10" x="4" y="4" rx="1.381"/>
<rect style="fill:#3a6be0" width="21" height="10" x="39" y="4" rx="1.4"/>
<rect style="fill:#3a6be0" width="29" height="10" x="4" y="49" rx="1.381"/>
<path style="fill:#ffffff;opacity:0.1" d="M 5.3808594 4 C 4.6158118 4 4 4.6158118 4 5.3808594 L 4 6.3808594 C 4 5.6158118 4.6158118 5 5.3808594 5 L 31.619141 5 C 32.384188 5 33 5.6158118 33 6.3808594 L 33 5.3808594 C 33 4.6158118 32.384188 4 31.619141 4 L 5.3808594 4 z M 40.400391 4 C 39.624791 4 39 4.6247906 39 5.4003906 L 39 6.4003906 C 39 5.6247906 39.624791 5 40.400391 5 L 58.599609 5 C 59.375209 5 60 5.6247906 60 6.4003906 L 60 5.4003906 C 60 4.6247906 59.375209 4 58.599609 4 L 40.400391 4 z M 5.3808594 49 C 4.6158118 49 4 49.615812 4 50.380859 L 4 51.380859 C 4 50.615812 4.6158118 50 5.3808594 50 L 31.619141 50 C 32.384188 50 33 50.615812 33 51.380859 L 33 50.380859 C 33 49.615812 32.384188 49 31.619141 49 L 5.3808594 49 z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -11,7 +11,7 @@
<meta name="title" content="ImHex">
<meta name="description" content="Free and extremely powerful Online Hex Editor for your Web Browser. ImHex is a free and open source Hex Editor for Reverse Engineers and Developers and Data Analysts.">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="apple-touch-icon" href="icon.png">
<link rel="apple-touch-icon" href="icon.svg">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
@@ -38,7 +38,7 @@
"founder": "WerWolv",
"slogan": "A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.",
"url": "https://imhex.werwolv.net",
"logo": "https://imhex.werwolv.net/assets/logos/logo.png"
"logo": "https://imhex.werwolv.net/assets/logos/logo.svg"
}
</script>

View File

@@ -10,8 +10,8 @@
],
"icons": [
{
"src": "icon.png",
"type": "image/png",
"src": "icon.svg",
"type": "image/svg",
"sizes": "640x640"
}
],

View File

@@ -261,4 +261,11 @@ function js_resizeCanvas() {
canvas.left = document.documentElement.clientLeft;
canvas.width = Math.min(document.documentElement.clientWidth, window.innerWidth || 0);
canvas.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 0);
}
}
// Prevent some default browser shortcuts from preventing ImHex ones to work
document.addEventListener('keydown', e => {
if (e.ctrlKey) {
if (e.which == 83) e.preventDefault();
}
})

1
lib/external/disassembler vendored Submodule

View File

@@ -38,6 +38,7 @@ set(LIBIMHEX_SOURCES
source/helpers/debugging.cpp
source/helpers/default_paths.cpp
source/helpers/imgui_hooks.cpp
source/helpers/semantic_version.cpp
source/test/tests.cpp
@@ -49,6 +50,7 @@ set(LIBIMHEX_SOURCES
source/ui/view.cpp
source/ui/popup.cpp
source/ui/toast.cpp
source/ui/banner.cpp
source/subcommands/subcommands.cpp
)
@@ -133,13 +135,14 @@ if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
if (WIN32)
set_target_properties(libimhex PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
target_link_options(libimhex PRIVATE -Wl,--export-all-symbols)
target_link_libraries(libimhex PRIVATE Netapi32.lib)
elseif (APPLE)
find_library(FOUNDATION NAMES Foundation)
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
endif ()
target_link_libraries(libimhex PRIVATE microtar libwolv ${NFD_LIBRARIES} magic dl ${JTHREAD_LIBRARIES})
target_link_libraries(libimhex PUBLIC libpl ${IMGUI_LIBRARIES})
target_link_libraries(libimhex PRIVATE microtar libwolv ${NFD_LIBRARIES} magic dl)
target_link_libraries(libimhex PUBLIC libpl ${IMGUI_LIBRARIES} ${JTHREAD_LIBRARIES})
precompileHeaders(libimhex "${CMAKE_CURRENT_SOURCE_DIR}/include")
endif()

View File

@@ -20,6 +20,7 @@ using ImGuiDataType = int;
using ImGuiInputTextFlags = int;
struct ImColor;
enum ImGuiCustomCol : int;
typedef int ImGuiColorEditFlags;
namespace hex {
@@ -43,7 +44,6 @@ namespace hex {
plugins when needed.
*/
namespace ContentRegistry {
/* Settings Registry. Allows adding of new entries into the ImHex preferences window. */
namespace Settings {
@@ -177,7 +177,7 @@ namespace hex {
class SliderDataSize : public Widget {
public:
SliderDataSize(u64 defaultValue, u64 min, u64 max) : m_value(defaultValue), m_min(min), m_max(max) { }
SliderDataSize(u64 defaultValue, u64 min, u64 max, u64 stepSize) : m_value(defaultValue), m_min(min), m_max(max), m_stepSize(stepSize) { }
bool draw(const std::string &name) override;
void load(const nlohmann::json &data) override;
@@ -188,11 +188,12 @@ namespace hex {
protected:
u64 m_value;
u64 m_min, m_max;
u64 m_stepSize;
};
class ColorPicker : public Widget {
public:
explicit ColorPicker(ImColor defaultColor);
explicit ColorPicker(ImColor defaultColor, ImGuiColorEditFlags flags = 0);
bool draw(const std::string &name) override;
@@ -202,12 +203,14 @@ namespace hex {
[[nodiscard]] ImColor getColor() const;
protected:
std::array<float, 4> m_value{};
std::array<float, 4> m_value = {}, m_defaultValue = {};
ImGuiColorEditFlags m_flags;
};
class DropDown : public Widget {
public:
explicit DropDown(const std::vector<std::string> &items, const std::vector<nlohmann::json> &settingsValues, const nlohmann::json &defaultItem) : m_items(items), m_settingsValues(settingsValues), m_defaultItem(defaultItem) { }
explicit DropDown(const std::vector<std::string> &items, const std::vector<nlohmann::json> &settingsValues, const nlohmann::json &defaultItem) : m_items(items.begin(), items.end()), m_settingsValues(settingsValues), m_defaultItem(defaultItem) { }
explicit DropDown(const std::vector<UnlocalizedString> &items, const std::vector<nlohmann::json> &settingsValues, const nlohmann::json &defaultItem) : m_items(items), m_settingsValues(settingsValues), m_defaultItem(defaultItem) { }
bool draw(const std::string &name) override;
@@ -218,7 +221,7 @@ namespace hex {
const nlohmann::json& getValue() const;
protected:
std::vector<std::string> m_items;
std::vector<UnlocalizedString> m_items;
std::vector<nlohmann::json> m_settingsValues;
nlohmann::json m_defaultItem;
@@ -623,8 +626,7 @@ namespace hex {
/* Data Inspector Registry. Allows adding of new types to the data inspector */
namespace DataInspector {
enum class NumberDisplayStyle
{
enum class NumberDisplayStyle : u8 {
Decimal,
Hexadecimal,
Octal
@@ -678,6 +680,13 @@ namespace hex {
std::optional<impl::EditingFunction> editingFunction = std::nullopt
);
/**
* @brief Allows adding new menu items to data inspector row context menus. Call this function inside the
* draw function of the data inspector row definition.
* @param function Callback that will draw menu items
*/
void drawMenuItems(const std::function<void()> &function);
}
/* Data Processor Node Registry. Allows adding new processor nodes to be used in the data processor */
@@ -1008,7 +1017,7 @@ namespace hex {
namespace impl {
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>;
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size, bool preview)>;
struct ExportMenuEntry {
UnlocalizedString unlocalizedName;
Callback callback;
@@ -1016,7 +1025,7 @@ namespace hex {
struct FindOccurrence {
Region region;
enum class DecodeType { ASCII, Binary, UTF16, Unsigned, Signed, Float, Double } decodeType;
enum class DecodeType { ASCII, UTF8, Binary, UTF16, Unsigned, Signed, Float, Double } decodeType;
std::endian endian = std::endian::native;
bool selected;
};
@@ -1354,6 +1363,7 @@ namespace hex {
}
/* Data Information Registry. Allows adding new analyzers to the data information view */
namespace DataInformation {
class InformationSection {
@@ -1420,6 +1430,54 @@ namespace hex {
}
/* Disassembler Registry. Allows adding new disassembler architectures */
namespace Disassembler {
struct Instruction {
u64 address;
u64 offset;
size_t size;
std::string bytes;
std::string mnemonic;
std::string operators;
};
class Architecture {
public:
explicit Architecture(std::string name) : m_name(std::move(name)) {}
virtual ~Architecture() = default;
virtual bool start() = 0;
virtual void end() = 0;
virtual std::optional<Instruction> disassemble(u64 imageBaseAddress, u64 instructionLoadAddress, u64 instructionDataAddress, std::span<const u8> code) = 0;
virtual void drawSettings() = 0;
[[nodiscard]] const std::string& getName() const { return m_name; }
private:
std::string m_name;
};
namespace impl {
using CreatorFunction = std::function<std::unique_ptr<Architecture>()>;
void addArchitectureCreator(CreatorFunction function);
const std::map<std::string, CreatorFunction>& getArchitectures();
}
template<std::derived_from<Architecture> T>
void add(auto && ...args) {
impl::addArchitectureCreator([...args = std::move(args)] {
return std::make_unique<T>(args...);
});
}
}
}
}

View File

@@ -11,7 +11,6 @@
#include <hex/api/imhex_api.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/patches.hpp>
#include <wolv/types/type_name.hpp>
@@ -32,15 +31,6 @@
#define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, false, __VA_ARGS__)
/* Forward declarations */
struct GLFWwindow;
namespace hex {
class Achievement;
class View;
}
namespace pl::ptrn { class Pattern; }
namespace hex {
namespace impl {
@@ -100,7 +90,8 @@ namespace hex {
/**
* @brief The EventManager allows subscribing to and posting events to different parts of the program.
* To create a new event, use the EVENT_DEF macro. This will create a new event type with the given name and parameters
* To create a new event, use the EVENT_DEF macro. This will create a new event type with the given name and parameters.
* Events should be created in an `events_*.hpp` category file under the `events` folder, and never directly here.
*/
class EventManager {
public:
@@ -200,122 +191,4 @@ namespace hex {
static void unsubscribe(void *token, impl::EventId id);
};
/* Default Events */
/**
* @brief Called when Imhex finished startup, and will enter the main window rendering loop
*/
EVENT_DEF(EventImHexStartupFinished);
EVENT_DEF(EventFileLoaded, std::fs::path);
EVENT_DEF(EventDataChanged, prv::Provider *);
EVENT_DEF(EventHighlightingChanged);
EVENT_DEF(EventWindowClosing, GLFWwindow *);
EVENT_DEF(EventRegionSelected, ImHexApi::HexEditor::ProviderRegion);
EVENT_DEF(EventAbnormalTermination, int);
EVENT_DEF(EventThemeChanged);
EVENT_DEF(EventOSThemeChanged);
EVENT_DEF(EventDPIChanged, float, float);
EVENT_DEF(EventWindowFocused, bool);
/**
* @brief Called when the provider is created.
* This event is responsible for (optionally) initializing the provider and calling EventProviderOpened
* (although the event can also be called manually without problem)
*/
EVENT_DEF(EventProviderCreated, prv::Provider *);
EVENT_DEF(EventProviderChanged, prv::Provider *, prv::Provider *);
/**
* @brief Called as a continuation of EventProviderCreated
* this event is normally called immediately after EventProviderCreated successfully initialized the provider.
* If no initialization (Provider::skipLoadInterface() has been set), this event should be called manually
* If skipLoadInterface failed, this event is not called
*
* @note this is not related to Provider::open()
*/
EVENT_DEF(EventProviderOpened, prv::Provider *);
EVENT_DEF(EventProviderClosing, prv::Provider *, bool *);
EVENT_DEF(EventProviderClosed, prv::Provider *);
EVENT_DEF(EventProviderDeleted, prv::Provider *);
EVENT_DEF(EventProviderSaved, prv::Provider *);
EVENT_DEF(EventWindowInitialized);
EVENT_DEF(EventWindowDeinitializing, GLFWwindow *);
EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&);
/**
* @brief Called upon creation of an IPS patch.
* As for now, the event only serves a purpose for the achievement unlock.
*/
EVENT_DEF(EventPatchCreated, const u8*, u64, const PatchKind);
EVENT_DEF(EventPatternEvaluating);
EVENT_DEF(EventPatternExecuted, const std::string&);
EVENT_DEF(EventPatternEditorChanged, const std::string&);
EVENT_DEF(EventStoreContentDownloaded, const std::fs::path&);
EVENT_DEF(EventStoreContentRemoved, const std::fs::path&);
EVENT_DEF(EventImHexClosing);
EVENT_DEF(EventAchievementUnlocked, const Achievement&);
EVENT_DEF(EventSearchBoxClicked, u32);
EVENT_DEF(EventViewOpened, View*);
EVENT_DEF(EventFirstLaunch);
EVENT_DEF(EventFileDragged, bool);
EVENT_DEF(EventFileDropped, std::fs::path);
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
EVENT_DEF(EventProviderDirtied, prv::Provider *);
/**
* @brief Called when a project has been loaded
*/
EVENT_DEF(EventProjectOpened);
EVENT_DEF_NO_LOG(EventFrameBegin);
EVENT_DEF_NO_LOG(EventFrameEnd);
EVENT_DEF_NO_LOG(EventSetTaskBarIconState, u32, u32, u32);
EVENT_DEF_NO_LOG(EventImGuiElementRendered, ImGuiID, const std::array<float, 4>&);
EVENT_DEF(RequestAddInitTask, std::string, bool, std::function<bool()>);
EVENT_DEF(RequestAddExitTask, std::string, std::function<bool()>);
EVENT_DEF(RequestOpenWindow, std::string);
EVENT_DEF(RequestHexEditorSelectionChange, Region);
EVENT_DEF(RequestPatternEditorSelectionChange, u32, u32);
EVENT_DEF(RequestJumpToPattern, const pl::ptrn::Pattern*);
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t, u64*);
EVENT_DEF(RequestRemoveBookmark, u64);
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
EVENT_DEF(RequestRunPatternCode);
EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path);
EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path);
EVENT_DEF(RequestUpdateWindowTitle);
EVENT_DEF(RequestCloseImHex, bool);
EVENT_DEF(RequestRestartImHex);
EVENT_DEF(RequestOpenFile, std::fs::path);
EVENT_DEF(RequestChangeTheme, std::string);
EVENT_DEF(RequestOpenPopup, std::string);
EVENT_DEF(RequestAddVirtualFile, std::fs::path, std::vector<u8>, Region);
/**
* @brief Creates a provider from it's unlocalized name, and add it to the provider list
*/
EVENT_DEF(RequestCreateProvider, std::string, bool, bool, hex::prv::Provider **);
EVENT_DEF(RequestInitThemeHandlers);
/**
* @brief Send an event to the main Imhex instance
*/
EVENT_DEF(SendMessageToMainInstance, const std::string, const std::vector<u8>&);
/**
* Move the data from all PerProvider instances from one provider to another.
* The 'from' provider should not have any per provider data after this, and should be immediately deleted
*/
EVENT_DEF(MovePerProviderData, prv::Provider *, prv::Provider *);
/**
* Called when ImHex managed to catch an error in a general try/catch to prevent/recover from a crash
*/
EVENT_DEF(EventCrashRecovered, const std::exception &);
}

View File

@@ -0,0 +1,120 @@
#pragma once
#include <hex/api/event_manager.hpp>
/* Forward declarations */
struct GLFWwindow;
namespace hex { class View; }
/* GUI events definitions */
namespace hex {
/**
* @brief Signals a newly opened window
*
* This event is sent when the window has just been opened and docked by the Window manager.
*
* FIXME: In the event that a newly created window is already docked, this will not be sent.
*
* FIXME: This is currently only used for the introduction tutorial.
* If the event's only purpose is this, maybe rename it?
*
* @param view the new view reference
*/
EVENT_DEF(EventViewOpened, View*);
/**
* @brief Signals a change in the DPI scale.
*
* This event is called once at startup to signal native scale definition (by passing the same value twice).
* On Windows OS, this event can also be posted if the window DPI has been changed.
*
* @param oldScale the old scale
* @param newScale the current scale that's now in use
*/
EVENT_DEF(EventDPIChanged, float, float);
/**
* @brief Signals the focus of the ImHex main window.
*
* This is directly tied as a GLFW window focus callback, and will be called accordingly when GLFW detects
* a change in focus.
*
* @param isFocused true if the window is focused
*/
EVENT_DEF(EventWindowFocused, bool);
/**
* @brief Signals a window being closed.
*
* Allows reactive clean up of running tasks, and prevents ImHex from closing
* by displaying an exit confirmation popup.
*
* @param window The window reference
*/
EVENT_DEF(EventWindowClosing, GLFWwindow*);
/**
* @brief Informs that the main window is initialized
*
* On Windows OS, it is used to initialize system theme, if ImHex's theme is following it.
*
* FIXME: Change event name to reflect Theme detection, if it's only used for that purpose?
*/
EVENT_DEF(EventWindowInitialized);
/**
* @brief Informs that the main window is deinitializing
*
* Allows for lifecycle cleanup before ImHex shutdown.
*
* @param window The window reference
*/
EVENT_DEF(EventWindowDeinitializing, GLFWwindow*);
/**
* @brief Signals a theme change in the host OS
*
* Allows ImHex to react to OS theme changes dynamically during execution.
*/
EVENT_DEF(EventOSThemeChanged);
}
/* silent (no-logging) GUI events definitions */
namespace hex {
/**
* @brief Signals the start of a new ImGui frame
*/
EVENT_DEF_NO_LOG(EventFrameBegin);
/**
* @brief Signals the end of an ImGui frame
*/
EVENT_DEF_NO_LOG(EventFrameEnd);
/**
* @brief Windows OS: Sets the taskbar icon state
*
* This event is used on Windows OS to display progress through the taskbar icon (the famous "green loading bar"
* in the taskbar).
*
* @param progressState the progress state (converted from the TaskProgressState enum)
* @param progressType the type of progress (converted from the TaskProgressType enum)
* @param percentage actual progress percentage (expected from 0 to 100)
*
* @see hex::ImHexApi::System::TaskProgressState
* @see hex::ImHexApi::System::TaskProgressType
*/
EVENT_DEF_NO_LOG(EventSetTaskBarIconState, u32, u32, u32);
/**
* @brief Informs of an ImGui element being rendered
*
* @param elementId the element's ID
* @param boundingBox the bounding box (composed of 4 floats)
*/
EVENT_DEF_NO_LOG(EventImGuiElementRendered, ImGuiID, const std::array<float, 4>&);
}

View File

@@ -0,0 +1,158 @@
#pragma once
#include <hex/api/event_manager.hpp>
#include <hex/helpers/patches.hpp>
/* Forward declarations */
namespace hex { class Achievement; }
/* Interaction events definitions */
namespace hex {
/**
* @brief Signals a file was loaded
*
* FIXME: this event is unused and should be scrapped.
*
* @param path the loaded file's path
*/
EVENT_DEF(EventFileLoaded, std::fs::path);
/**
* @brief Signals a change in the current data
*
* Enables provider reaction to data change, especially the data inspector.
*
* This is caused by the following:
* - an explicit provider reload, requested by the user (Ctrl+R)
* - any user action that results in the creation of an "undo" stack action (generally a data modification)
*
* @param provider the Provider subject to the data change
*/
EVENT_DEF(EventDataChanged, prv::Provider *);
/**
* @brief Signals a change in highlighting
*
* The event's only purpose is for the Hex editor to clear highlights when receiving this event.
*/
EVENT_DEF(EventHighlightingChanged);
/**
* @brief Informs of a provider region being selected
*
* This is very generally used to signal user actions that select a specific region within the provider.
* It is also used to pass on regions when the provider changes.
*
* @param providerRegion the provider-aware region being selected
*/
EVENT_DEF(EventRegionSelected, ImHexApi::HexEditor::ProviderRegion);
/**
* @brief Signals a theme change
*
* On Windows OS, this is used to reflect the theme color onto the window frame.
*/
EVENT_DEF(EventThemeChanged);
/**
* @brief Signals that a bookmark was created
*
* For now, this event's only purpose is to unlock an achievement.
*
* @param entry the new bookmark
*/
EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&);
/**
* @brief Called upon creation of an IPS patch.
* As for now, the event only serves a purpose for the achievement unlock.
*
* @param data the pointer to the patch content's start
* @param size the patch data size
* @param kind the patch's kind
*/
EVENT_DEF(EventPatchCreated, const u8*, u64, const PatchKind);
/**
* @brief Signals the beginning of evaluation of the current pattern
*
* This allows resetting the drawer view for the pattern data while we wait for the execution completion.
*/
EVENT_DEF(EventPatternEvaluating);
/**
* @brief Signals the completion of the pattern evaluation
*
* This causes another reset in the drawer view, to refresh the table displayed to the user.
*
* @param code the execution's status code
*/
EVENT_DEF(EventPatternExecuted, const std::string&);
/**
* @brief Denotes when pattern editor has changed
*
* FIXME: this event is unused and should be scrapped.
*/
EVENT_DEF(EventPatternEditorChanged, const std::string&);
/**
* @brief Signals that a Content Store item was downloaded
*
* FIXME: this event is unused and should be scrapped.
*
* @param path the item's path on the filesystem
*/
EVENT_DEF(EventStoreContentDownloaded, const std::fs::path&);
/**
* @brief Signals the removal of a Content Store item
*
* Note: at the time of the event firing, the item has already been removed from the filesystem.
*
* FIXME: this event is unused and should be scrapped.
*
* @param path the item's old file path where it used to be in the filesystem
*/
EVENT_DEF(EventStoreContentRemoved, const std::fs::path&);
/**
* @brief Signals the unlocking of an achievement
*
* This is used by the achievement manager to refresh the achievement display, as well as store progress to
* the appropriate storage file.
*
* @param achievement the achievement that was unlocked
*/
EVENT_DEF(EventAchievementUnlocked, const Achievement&);
/**
* @brief Signals a click on the search box
*
* As there are different behaviours depending on the click (left or right) done by the user,
* this allows the consequences of said click to be registered in their own components.
*
* @param button the ImGuiMouseButton's value
*/
EVENT_DEF(EventSearchBoxClicked, u32);
/**
* @brief Updates on whether a file is being dragged into ImHex
*
* Allows ImGUi to display a file dragging information on screen when a file is being dragged.
*
* @param isFileDragged true if a file is being dragged
*/
EVENT_DEF(EventFileDragged, bool);
/**
* @brief Triggers loading when a file is dropped
*
* The event fires when a file is dropped into ImHex, which passes it to file handlers to load it.
*
* @param path the dropped file's path
*/
EVENT_DEF(EventFileDropped, std::fs::path);
}

View File

@@ -0,0 +1,72 @@
#pragma once
#include <hex/api/event_manager.hpp>
/* Lifecycle events definitions */
namespace hex {
/**
* @brief Called when Imhex finished startup, and will enter the main window rendering loop
*/
EVENT_DEF(EventImHexStartupFinished);
/**
* @brief Called when ImHex is closing, to trigger the last shutdown hooks
*
* This is the last event to fire before complete graceful shutdown.
*/
EVENT_DEF(EventImHexClosing);
/**
* @brief Signals that it's ImHex first launch ever
*
* This event allows for the launch of the ImHex tutorial (also called Out of Box experience).
*/
EVENT_DEF(EventFirstLaunch);
/**
* FIXME: this event is unused and should be scrapped.
*/
EVENT_DEF(EventAnySettingChanged);
/**
* @brief Ensures correct plugin cleanup on crash
*
* This event is fired when catching an unexpected error that cannot be recovered and
* which forces Imhex to close immediately.
*
* Subscribing to this event ensures that the plugin can correctly clean up any mission-critical tasks
* before forceful shutdown.
*
* @param signal the POSIX signal code
*/
EVENT_DEF(EventAbnormalTermination, int);
/**
* @brief Informs of the ImHex versions (and difference, if any)
*
* Called on every startup to inform subscribers of the two versions picked up:
* - the version of the previous launch, gathered from the settings file
* - the current version, gathered directly from C++ code
*
* In most cases, and unless ImHex was updated, the two parameters will be the same.
*
* FIXME: Maybe rename the event to signal a startup information, instead of the misleading
* title that the event could be fired when ImHex detects that it was updated since last launch?
*
* @param previousLaunchVersion ImHex's version during the previous launch
* @param currentVersion ImHex's current version for this startup
*/
EVENT_DEF(EventImHexUpdated, SemanticVersion, SemanticVersion);
/**
* @brief Called when ImHex managed to catch an error in a general try/catch to prevent/recover from a crash
*/
EVENT_DEF(EventCrashRecovered, const std::exception &);
/**
* @brief Called when a project has been loaded
*/
EVENT_DEF(EventProjectOpened);
}

View File

@@ -0,0 +1,113 @@
#pragma once
#include <hex.hpp>
#include <hex/api/event_manager.hpp>
/* Provider events definitions */
namespace hex {
/**
* @brief Called when the provider is created.
* This event is responsible for (optionally) initializing the provider and calling EventProviderOpened
* (although the event can also be called manually without problem)
*/
EVENT_DEF(EventProviderCreated, prv::Provider *);
/**
* @brief Called as a continuation of EventProviderCreated
* this event is normally called immediately after EventProviderCreated successfully initialized the provider.
* If no initialization (Provider::skipLoadInterface() has been set), this event should be called manually
* If skipLoadInterface failed, this event is not called
*
* @note this is not related to Provider::open()
*/
EVENT_DEF(EventProviderOpened, prv::Provider *);
/**
* @brief Signals a change in provider (in-place)
*
* Note: if the provider was deleted, the new ("current") provider will be `nullptr`
*
* @param oldProvider the old provider
* @param currentProvider the current provider
*/
EVENT_DEF(EventProviderChanged, prv::Provider *, prv::Provider *);
/**
* @brief Signals that a provider was saved
*
* @param provider the saved provider
*/
EVENT_DEF(EventProviderSaved, prv::Provider *);
/**
* @brief Signals a provider is closing
*
* FIXME: as for now, this behaves as a request more than an event. Also, the boolean is always set to true,
* and serves no purpose. This should be moved into the Provider requests section and declared accordingly.
*
* @param provider the closing provider
* @param shouldClose whether the provider should close
*/
EVENT_DEF(EventProviderClosing, prv::Provider *, bool *);
/**
* @brief Signals that a provider was closed
*
* As this is a closure information broadcast, the provider should generally not be accessed, as it could
* result in problems.
*
* @param provider the now-closed provider
*/
EVENT_DEF(EventProviderClosed, prv::Provider *);
/**
* @brief Signals that a provider is being deleted
*
* Provider's data should not be accessed.
*
* @param provider the provider
*/
EVENT_DEF(EventProviderDeleted, prv::Provider *);
}
/* Provider data events definitions */
namespace hex {
/**
* @brief Signals the dirtying of a provider
*
* Any data modification that occurs in a provider dirties it, until its state is either saved or restored.
* This event signals that fact to subscribers so additional code can be executed for certain cases.
*/
EVENT_DEF(EventProviderDirtied, prv::Provider *);
/**
* @brief Signals an insertion of new data into a provider
*
* @param provider the provider
* @param offset the start of the insertion
* @param size the new data's size
*/
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
/**
* @brief Signals a modification in the provider's data
*
* @param provider the provider
* @param offset the data modification's offset (start address)
* @param size the buffer's size
* @param buffer the modified data written at this address
*/
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
/**
* @brief Signals a removal of some of the provider's data
*
* @param provider the provider
* @param offset the deletion offset (start address)
* @param size the deleted data's size
*/
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include <hex/api/event_manager.hpp>
/* GUI requests definitions */
namespace hex {
/**
* @brief Requests the opening of a new window.
*
* @param name the window's name
*/
EVENT_DEF(RequestOpenWindow, std::string);
/**
* @brief Centralized request to update ImHex's main window title
*
* This request can be called to make ImHex refresh its main window title, taking into account a new project
* or file opened/closed.
*/
EVENT_DEF(RequestUpdateWindowTitle);
/**
* @brief Requests a theme type (light or dark) change
*
* @param themeType either `Light` or `Dark`
*/
EVENT_DEF(RequestChangeTheme, std::string);
/**
* @brief Requests the opening of a popup
*
* @param name the popup's name
*/
EVENT_DEF(RequestOpenPopup, std::string);
}

View File

@@ -0,0 +1,116 @@
#pragma once
#include <hex.hpp>
#include <hex/api/event_manager.hpp>
/* Forward declarations */
namespace pl::ptrn { class Pattern; }
/* Interaction requests definitions */
namespace hex {
/**
* @brief Requests a selection change in the Hex editor
*
* This request is handled by the Hex editor, which proceeds to check if the selection is valid.
* If it is invalid, the Hex editor fires the `EventRegionSelected` event with nullptr region info.
*
* @param region the region that should be selected
*/
EVENT_DEF(RequestHexEditorSelectionChange, Region);
/**
* @brief Requests the Pattern editor to move selection
*
* Requests the Pattern editor to move the cursor's position to reflect the user's click or movement.
*
* @param line the target line
* @param column the target column
*/
EVENT_DEF(RequestPatternEditorSelectionChange, u32, u32);
/**
* @brief Requests a jump to a given pattern
*
* This request is fired by the Hex editor when the user asks to jump to the pattern.
* It is then caught and reflected by the Pattern data component.
*
* @param pattern the pattern to jump to
*/
EVENT_DEF(RequestJumpToPattern, const pl::ptrn::Pattern*);
/**
* @brief Requests to add a bookmark
*
* @param region the region to be bookmarked
* @param name the bookmark's name
* @param comment a comment
* @param color the color
* @param id the bookmark's unique ID
*/
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t, u64*);
/**
* @brief Requests a bookmark removal
*
* @param id the bookmark's unique ID
*/
EVENT_DEF(RequestRemoveBookmark, u64);
/**
* @brief Request the Pattern editor to set its code
*
* This request allows the rest of ImHex to interface with the Pattern editor component, by setting its code.
* This allows for `.hexpat` file loading, and more.
*
* @param code the code's string
*/
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
/**
* @brief Requests the Pattern editor to run the current code
*
* This is only ever used in the introduction tutorial.
*
* FIXME: the name is misleading, as for now this activates the pattern's auto-evaluation rather than a
* one-off execution
*/
EVENT_DEF(RequestRunPatternCode);
/**
* @brief Request to load a pattern language file
*
* FIXME: this request is unused, as now another component is responsible for pattern file loading.
* This request should be scrapped.
*
* @param path the pattern file's path
*/
EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path);
/**
* @brief Request to save a pattern language file
*
* FIXME: this request is unused, as now another component is responsible for pattern file saving.
* This request should be scrapped.
*
* @param path the pattern file's path
*/
EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path);
/**
* @brief Requests ImHex to open and process a file
*
* @param path the file's path
*/
EVENT_DEF(RequestOpenFile, std::fs::path);
/**
* @brief Adds a virtual file in the Pattern editor
*
* @param path the file's path
* @param data the file's data
* @param region the impacted region
*/
EVENT_DEF(RequestAddVirtualFile, std::fs::path, std::vector<u8>, Region);
}

View File

@@ -0,0 +1,84 @@
#pragma once
#include <hex.hpp>
#include <hex/api/event_manager.hpp>
/* Lifecycle requests definitions */
namespace hex {
/**
* @brief Emit a request to add an initialization task to the list
*
* These tasks will be executed at startup.
*
* @param name Name of the init task
* @param isAsync Whether the task is asynchronous (true if yes)
* @param callbackFunction The function to call to execute the task
*/
EVENT_DEF(RequestAddInitTask, std::string, bool, std::function<bool()>);
/**
* @brief Emit a request to add an exit task to the list
*
* These tasks will be executed during the exit phase.
*
* FIXME: request is unused and should be scrapped.
*
* @param name Name of the exit task
* @param callbackFunction The function to call to execute the task
*/
EVENT_DEF(RequestAddExitTask, std::string, std::function<bool()>);
/**
* @brief Requests ImHex's graceful shutdown
*
* If there are no questions (bool set to true), ImHex closes immediately.
* If set to false, there is a procedure run to prompt a confirmation to the user.
*
* @param noQuestions true if no questions
*/
EVENT_DEF(RequestCloseImHex, bool);
/**
* @brief Requests ImHex's restart
*
* This event is necessary for ImHex to restart in the main loop for native and web platforms,
* as ImHex cannot simply close and re-open.
*
* This event serves no purpose on Linux, Windows and macOS platforms.
*/
EVENT_DEF(RequestRestartImHex);
/**
* @brief Requests the initialization of theme handlers
*
* This is called during ImGui bootstrapping, and should not be called at any other time.
*/
EVENT_DEF(RequestInitThemeHandlers);
/**
* @brief Requests version and first-startup checks
*
* This request is called during ImHex's startup, and allows ImHex to check if it was updated since last launch.
* It also ensures newcomers (that open ImHex for the first time) are greeted with the tutorial.
*
* FIXME: the name is misleading, as this request does not effectively start any migration. It only executes
* checks about ImHex's version. The name should be changed to reflect this behaviour.
*/
EVENT_DEF(RequestStartMigration);
/**
* @brief Send a subcommand to the main Imhex instance
*
* This request is called to send a subcommand to the main ImHex instance.
* This subcommand will then be executed by a handler when ImHex finishing initializing
* (`EventImHexStartupFinished`).
*
* FIXME: change the name so that it is prefixed with "Request" like every other request.
*
* @param name the subcommand's name
* @param data the subcommand's data
*/
EVENT_DEF(SendMessageToMainInstance, const std::string, const std::vector<u8>&);
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include <hex/api/event_manager.hpp>
/* Provider requests definitions */
namespace hex {
/**
* @brief Creates a provider from its unlocalized name, and add it to the provider list
*/
EVENT_DEF(RequestCreateProvider, std::string, bool, bool, hex::prv::Provider **);
/**
* @brief Move the data from all PerProvider instances from one provider to another
*
* The 'from' provider should not have any per provider data after this, and should be immediately deleted
*
* FIXME: rename with the "Request" prefix to apply standard naming convention.
*/
EVENT_DEF(MovePerProviderData, prv::Provider *, prv::Provider *);
}

View File

@@ -2,6 +2,7 @@
#include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/helpers/semantic_version.hpp>
#include <functional>
#include <optional>
@@ -492,6 +493,7 @@ namespace hex {
*/
float getNativeScale();
float getBackingScaleFactor();
/**
* @brief Gets the current main window position
@@ -580,6 +582,14 @@ namespace hex {
*/
const std::string& getGLRenderer();
/**
* @brief Checks if ImHex is being run in a "Corporate Environment"
* This function simply checks for common telltale signs such as if the machine is joined a
* domain. It's not super accurate, but it's still useful for statistics
* @return True if it is
*/
bool isCorporateEnvironment();
/**
* @brief Checks if ImHex is running in portable mode
* @return Whether ImHex is running in portable mode
@@ -618,7 +628,7 @@ namespace hex {
* @brief Gets the current ImHex version
* @return ImHex version
*/
std::string getImHexVersion(bool withBuildType = true);
SemanticVersion getImHexVersion();
/**
* @brief Gets the current git commit hash
@@ -695,6 +705,13 @@ namespace hex {
*/
void* getLibImHexModuleHandle();
/**
* Adds a new migration routine that will be executed when upgrading from a lower version than specified in migrationVersion
* @param migrationVersion Upgrade point version
* @param function Function to run
*/
void addMigrationRoutine(SemanticVersion migrationVersion, std::function<void()> function);
}
/**
@@ -736,11 +753,8 @@ namespace hex {
const std::vector<Font>& getFonts();
void setCustomFontPath(const std::fs::path &path);
void setFontSize(float size);
void setFontAtlas(ImFontAtlas *fontAtlas);
std::map<UnlocalizedString, ImFont*>& getFontDefinitions();
void setFonts(ImFont *bold, ImFont *italic);
}
GlyphRange glyph(const char *glyph);
@@ -753,26 +767,8 @@ namespace hex {
constexpr static float DefaultFontSize = 13.0;
ImFont* Bold();
ImFont* Italic();
/**
* @brief Gets the current custom font path
* @return The current custom font path
*/
const std::filesystem::path& getCustomFontPath();
/**
* @brief Gets the current font size
* @return The current font size
*/
float getFontSize();
/**
* @brief Gets the current font atlas
* @return Current font atlas
*/
ImFontAtlas* getFontAtlas();
void registerFont(const UnlocalizedString &fontName);
ImFont* getFont(const UnlocalizedString &fontName);
}

View File

@@ -31,7 +31,7 @@ namespace hex {
}
void loadLanguage(const std::string &language);
void loadLanguage(std::string language);
std::string getLocalizedString(const std::string &unlocalizedString, const std::string &language = "");
[[nodiscard]] const std::map<std::string, std::string> &getSupportedLanguages();

View File

@@ -2,137 +2,25 @@
#include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/helpers/keys.hpp>
#include <functional>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <GLFW/glfw3.h>
struct ImGuiWindow;
struct KeyEquivalent {
bool valid;
bool ctrl, opt, cmd, shift;
int key;
};
namespace hex {
class View;
enum class Keys : u32 {
Space = GLFW_KEY_SPACE,
Apostrophe = GLFW_KEY_APOSTROPHE,
Comma = GLFW_KEY_COMMA,
Minus = GLFW_KEY_MINUS,
Period = GLFW_KEY_PERIOD,
Slash = GLFW_KEY_SLASH,
Num0 = GLFW_KEY_0,
Num1 = GLFW_KEY_1,
Num2 = GLFW_KEY_2,
Num3 = GLFW_KEY_3,
Num4 = GLFW_KEY_4,
Num5 = GLFW_KEY_5,
Num6 = GLFW_KEY_6,
Num7 = GLFW_KEY_7,
Num8 = GLFW_KEY_8,
Num9 = GLFW_KEY_9,
Semicolon = GLFW_KEY_SEMICOLON,
Equals = GLFW_KEY_EQUAL,
A = GLFW_KEY_A,
B = GLFW_KEY_B,
C = GLFW_KEY_C,
D = GLFW_KEY_D,
E = GLFW_KEY_E,
F = GLFW_KEY_F,
G = GLFW_KEY_G,
H = GLFW_KEY_H,
I = GLFW_KEY_I,
J = GLFW_KEY_J,
K = GLFW_KEY_K,
L = GLFW_KEY_L,
M = GLFW_KEY_M,
N = GLFW_KEY_N,
O = GLFW_KEY_O,
P = GLFW_KEY_P,
Q = GLFW_KEY_Q,
R = GLFW_KEY_R,
S = GLFW_KEY_S,
T = GLFW_KEY_T,
U = GLFW_KEY_U,
V = GLFW_KEY_V,
W = GLFW_KEY_W,
X = GLFW_KEY_X,
Y = GLFW_KEY_Y,
Z = GLFW_KEY_Z,
LeftBracket = GLFW_KEY_LEFT_BRACKET,
Backslash = GLFW_KEY_BACKSLASH,
RightBracket = GLFW_KEY_RIGHT_BRACKET,
GraveAccent = GLFW_KEY_GRAVE_ACCENT,
World1 = GLFW_KEY_WORLD_1,
World2 = GLFW_KEY_WORLD_2,
Escape = GLFW_KEY_ESCAPE,
Enter = GLFW_KEY_ENTER,
Tab = GLFW_KEY_TAB,
Backspace = GLFW_KEY_BACKSPACE,
Insert = GLFW_KEY_INSERT,
Delete = GLFW_KEY_DELETE,
Right = GLFW_KEY_RIGHT,
Left = GLFW_KEY_LEFT,
Down = GLFW_KEY_DOWN,
Up = GLFW_KEY_UP,
PageUp = GLFW_KEY_PAGE_UP,
PageDown = GLFW_KEY_PAGE_DOWN,
Home = GLFW_KEY_HOME,
End = GLFW_KEY_END,
CapsLock = GLFW_KEY_CAPS_LOCK,
ScrollLock = GLFW_KEY_SCROLL_LOCK,
NumLock = GLFW_KEY_NUM_LOCK,
PrintScreen = GLFW_KEY_PRINT_SCREEN,
Pause = GLFW_KEY_PAUSE,
F1 = GLFW_KEY_F1,
F2 = GLFW_KEY_F2,
F3 = GLFW_KEY_F3,
F4 = GLFW_KEY_F4,
F5 = GLFW_KEY_F5,
F6 = GLFW_KEY_F6,
F7 = GLFW_KEY_F7,
F8 = GLFW_KEY_F8,
F9 = GLFW_KEY_F9,
F10 = GLFW_KEY_F10,
F11 = GLFW_KEY_F11,
F12 = GLFW_KEY_F12,
F13 = GLFW_KEY_F13,
F14 = GLFW_KEY_F14,
F15 = GLFW_KEY_F15,
F16 = GLFW_KEY_F16,
F17 = GLFW_KEY_F17,
F18 = GLFW_KEY_F18,
F19 = GLFW_KEY_F19,
F20 = GLFW_KEY_F20,
F21 = GLFW_KEY_F21,
F22 = GLFW_KEY_F22,
F23 = GLFW_KEY_F23,
F24 = GLFW_KEY_F24,
F25 = GLFW_KEY_F25,
KeyPad0 = GLFW_KEY_KP_0,
KeyPad1 = GLFW_KEY_KP_1,
KeyPad2 = GLFW_KEY_KP_2,
KeyPad3 = GLFW_KEY_KP_3,
KeyPad4 = GLFW_KEY_KP_4,
KeyPad5 = GLFW_KEY_KP_5,
KeyPad6 = GLFW_KEY_KP_6,
KeyPad7 = GLFW_KEY_KP_7,
KeyPad8 = GLFW_KEY_KP_8,
KeyPad9 = GLFW_KEY_KP_9,
KeyPadDecimal = GLFW_KEY_KP_DECIMAL,
KeyPadDivide = GLFW_KEY_KP_DIVIDE,
KeyPadMultiply = GLFW_KEY_KP_MULTIPLY,
KeyPadSubtract = GLFW_KEY_KP_SUBTRACT,
KeyPadAdd = GLFW_KEY_KP_ADD,
KeyPadEnter = GLFW_KEY_KP_ENTER,
KeyPadEqual = GLFW_KEY_KP_EQUAL,
Menu = GLFW_KEY_MENU,
};
class Key {
public:
constexpr Key() = default;
@@ -153,12 +41,7 @@ namespace hex {
constexpr static auto SUPER = Key(static_cast<Keys>(0x0800'0000));
constexpr static auto CurrentView = Key(static_cast<Keys>(0x1000'0000));
constexpr static auto AllowWhileTyping = Key(static_cast<Keys>(0x2000'0000));
#if defined (OS_MACOS)
constexpr static auto CTRLCMD = SUPER;
#else
constexpr static auto CTRLCMD = CTRL;
#endif
constexpr static auto CTRLCMD = Key(static_cast<Keys>(0x4000'0000));
class Shortcut {
public:
@@ -180,6 +63,7 @@ namespace hex {
bool isLocal() const;
std::string toString() const;
KeyEquivalent toKeyEquivalent() const;
const std::set<Key>& getKeys() const;
bool has(Key key) const;
bool matches(const Shortcut &other) const;
@@ -199,10 +83,12 @@ namespace hex {
class ShortcutManager {
public:
using Callback = std::function<void()>;
using EnabledCallback = std::function<bool()>;
struct ShortcutEntry {
Shortcut shortcut;
std::vector<UnlocalizedString> unlocalizedName;
Callback callback;
EnabledCallback enabledCallback;
};
/**
@@ -210,9 +96,10 @@ namespace hex {
* @param shortcut The shortcut to add.
* @param unlocalizedName The unlocalized name of the shortcut
* @param callback The callback to call when the shortcut is triggered.
* @param enabledCallback Callback that's called to check if this shortcut is enabled
*/
static void addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const Callback &callback);
static void addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
static void addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const Callback &callback, const EnabledCallback &enabledCallback = []{ return true; });
static void addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback, const EnabledCallback &enabledCallback = []{ return true; });
/**
* @brief Add a view-specific shortcut. View-specific shortcuts can only be triggered when the specified view is focused.
@@ -220,9 +107,10 @@ namespace hex {
* @param shortcut The shortcut to add.
* @param unlocalizedName The unlocalized name of the shortcut
* @param callback The callback to call when the shortcut is triggered.
* @param enabledCallback Callback that's called to check if this shortcut is enabled
*/
static void addShortcut(View *view, const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const Callback &callback);
static void addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
static void addShortcut(View *view, const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const Callback &callback, const EnabledCallback &enabledCallback = []{ return true; });
static void addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback, const EnabledCallback &enabledCallback = []{ return true; });
/**
@@ -255,6 +143,11 @@ namespace hex {
static void resumeShortcuts();
static void pauseShortcuts();
static void enableMacOSMode();
[[nodiscard]] static std::optional<UnlocalizedString> getLastActivatedMenu();
static void resetLastActivatedMenu();
[[nodiscard]] static std::optional<Shortcut> getPreviousShortcut();
[[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts();

View File

@@ -67,6 +67,7 @@ namespace hex {
static void reset();
static void setAccentColor(const ImColor &color);
public:
struct ThemeHandler {
@@ -82,6 +83,7 @@ namespace hex {
static const std::map<std::string, ThemeHandler>& getThemeHandlers();
static const std::map<std::string, StyleHandler>& getStyleHandlers();
private:
ThemeManager() = default;
};

View File

@@ -151,6 +151,9 @@ namespace hex {
static void addInteractiveHelpText(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, UnlocalizedString unlocalizedString);
static void addInteractiveHelpLink(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, std::string link);
static void setLastItemInteractiveHelpPopup(std::function<void()> callback);
static void setLastItemInteractiveHelpLink(std::string link);
/**
* @brief Draws the tutorial

View File

@@ -1,6 +1,5 @@
#pragma once
#include <hex/api/event_manager.hpp>
#include <hex/api/imhex_api.hpp>
namespace hex {

View File

@@ -44,4 +44,7 @@ namespace hex::dbg {
}
}
bool debugModeEnabled();
void setDebugModeEnabled(bool enabled);
}

View File

@@ -82,8 +82,9 @@ namespace hex::paths {
const static inline impl::DataPath Nodes("scripts/nodes");
const static inline impl::DataPath Layouts("layouts");
const static inline impl::DataPath Workspaces("workspaces");
const static inline impl::DataPath Disassemblers("disassemblers");
constexpr static inline std::array<const impl::DefaultPath*, 20> All = {
constexpr static inline std::array<const impl::DefaultPath*, 21> All = {
&Config,
&Recent,
@@ -106,6 +107,7 @@ namespace hex::paths {
&Nodes,
&Layouts,
&Workspaces,
&Disassemblers
};
}

View File

@@ -0,0 +1,122 @@
#pragma once
#include <GLFW/glfw3.h>
#if defined(__cplusplus)
enum class Keys {
#else
enum Keys {
#endif
Space = GLFW_KEY_SPACE,
Apostrophe = GLFW_KEY_APOSTROPHE,
Comma = GLFW_KEY_COMMA,
Minus = GLFW_KEY_MINUS,
Period = GLFW_KEY_PERIOD,
Slash = GLFW_KEY_SLASH,
Num0 = GLFW_KEY_0,
Num1 = GLFW_KEY_1,
Num2 = GLFW_KEY_2,
Num3 = GLFW_KEY_3,
Num4 = GLFW_KEY_4,
Num5 = GLFW_KEY_5,
Num6 = GLFW_KEY_6,
Num7 = GLFW_KEY_7,
Num8 = GLFW_KEY_8,
Num9 = GLFW_KEY_9,
Semicolon = GLFW_KEY_SEMICOLON,
Equals = GLFW_KEY_EQUAL,
A = GLFW_KEY_A,
B = GLFW_KEY_B,
C = GLFW_KEY_C,
D = GLFW_KEY_D,
E = GLFW_KEY_E,
F = GLFW_KEY_F,
G = GLFW_KEY_G,
H = GLFW_KEY_H,
I = GLFW_KEY_I,
J = GLFW_KEY_J,
K = GLFW_KEY_K,
L = GLFW_KEY_L,
M = GLFW_KEY_M,
N = GLFW_KEY_N,
O = GLFW_KEY_O,
P = GLFW_KEY_P,
Q = GLFW_KEY_Q,
R = GLFW_KEY_R,
S = GLFW_KEY_S,
T = GLFW_KEY_T,
U = GLFW_KEY_U,
V = GLFW_KEY_V,
W = GLFW_KEY_W,
X = GLFW_KEY_X,
Y = GLFW_KEY_Y,
Z = GLFW_KEY_Z,
LeftBracket = GLFW_KEY_LEFT_BRACKET,
Backslash = GLFW_KEY_BACKSLASH,
RightBracket = GLFW_KEY_RIGHT_BRACKET,
GraveAccent = GLFW_KEY_GRAVE_ACCENT,
World1 = GLFW_KEY_WORLD_1,
World2 = GLFW_KEY_WORLD_2,
Escape = GLFW_KEY_ESCAPE,
Enter = GLFW_KEY_ENTER,
Tab = GLFW_KEY_TAB,
Backspace = GLFW_KEY_BACKSPACE,
Insert = GLFW_KEY_INSERT,
Delete = GLFW_KEY_DELETE,
Right = GLFW_KEY_RIGHT,
Left = GLFW_KEY_LEFT,
Down = GLFW_KEY_DOWN,
Up = GLFW_KEY_UP,
PageUp = GLFW_KEY_PAGE_UP,
PageDown = GLFW_KEY_PAGE_DOWN,
Home = GLFW_KEY_HOME,
End = GLFW_KEY_END,
CapsLock = GLFW_KEY_CAPS_LOCK,
ScrollLock = GLFW_KEY_SCROLL_LOCK,
NumLock = GLFW_KEY_NUM_LOCK,
PrintScreen = GLFW_KEY_PRINT_SCREEN,
Pause = GLFW_KEY_PAUSE,
F1 = GLFW_KEY_F1,
F2 = GLFW_KEY_F2,
F3 = GLFW_KEY_F3,
F4 = GLFW_KEY_F4,
F5 = GLFW_KEY_F5,
F6 = GLFW_KEY_F6,
F7 = GLFW_KEY_F7,
F8 = GLFW_KEY_F8,
F9 = GLFW_KEY_F9,
F10 = GLFW_KEY_F10,
F11 = GLFW_KEY_F11,
F12 = GLFW_KEY_F12,
F13 = GLFW_KEY_F13,
F14 = GLFW_KEY_F14,
F15 = GLFW_KEY_F15,
F16 = GLFW_KEY_F16,
F17 = GLFW_KEY_F17,
F18 = GLFW_KEY_F18,
F19 = GLFW_KEY_F19,
F20 = GLFW_KEY_F20,
F21 = GLFW_KEY_F21,
F22 = GLFW_KEY_F22,
F23 = GLFW_KEY_F23,
F24 = GLFW_KEY_F24,
F25 = GLFW_KEY_F25,
KeyPad0 = GLFW_KEY_KP_0,
KeyPad1 = GLFW_KEY_KP_1,
KeyPad2 = GLFW_KEY_KP_2,
KeyPad3 = GLFW_KEY_KP_3,
KeyPad4 = GLFW_KEY_KP_4,
KeyPad5 = GLFW_KEY_KP_5,
KeyPad6 = GLFW_KEY_KP_6,
KeyPad7 = GLFW_KEY_KP_7,
KeyPad8 = GLFW_KEY_KP_8,
KeyPad9 = GLFW_KEY_KP_9,
KeyPadDecimal = GLFW_KEY_KP_DECIMAL,
KeyPadDivide = GLFW_KEY_KP_DIVIDE,
KeyPadMultiply = GLFW_KEY_KP_MULTIPLY,
KeyPadSubtract = GLFW_KEY_KP_SUBTRACT,
KeyPadAdd = GLFW_KEY_KP_ADD,
KeyPadEnter = GLFW_KEY_KP_ENTER,
KeyPadEqual = GLFW_KEY_KP_EQUAL,
Menu = GLFW_KEY_MENU,
};

View File

@@ -807,6 +807,8 @@ namespace hex::gl {
void bind() const;
void unbind() const;
bool isValid() const { return m_program != 0; }
void setUniform(std::string_view name, const int &value);
void setUniform(std::string_view name, const float &value);

View File

@@ -0,0 +1,36 @@
#pragma once
#include <hex.hpp>
#include <compare>
#include <string>
#include <vector>
namespace hex {
class SemanticVersion {
public:
SemanticVersion() = default;
SemanticVersion(std::string version);
SemanticVersion(std::string_view version);
SemanticVersion(const char *version);
std::strong_ordering operator<=>(const SemanticVersion &) const;
bool operator==(const SemanticVersion &other) const;
u32 major() const;
u32 minor() const;
u32 patch() const;
bool nightly() const;
const std::string& buildType() const;
bool isValid() const;
std::string get(bool withBuildType = true) const;
private:
std::vector<std::string> m_parts;
std::string m_buildType;
};
}

View File

@@ -26,7 +26,7 @@
#include <hex/helpers/utils_linux.hpp>
#endif
struct ImVec2;
#include <imgui.h>
namespace hex {
@@ -340,4 +340,6 @@ namespace hex {
*/
[[nodiscard]] void* getContainingModule(void* symbol);
[[nodiscard]] std::optional<ImColor> blendColors(const std::optional<ImColor> &a, const std::optional<ImColor> &b);
}

View File

@@ -1,5 +1,7 @@
#pragma once
#include <hex/helpers/keys.hpp>
#if defined(OS_MACOS)
struct GLFWwindow;
@@ -17,8 +19,11 @@
void enumerateFontsMacos();
void macosHandleTitlebarDoubleClickGesture(GLFWwindow *window);
void macosSetWindowMovable(GLFWwindow *window, bool movable);
bool macosIsWindowBeingResizedByUser(GLFWwindow *window);
void macosMarkContentEdited(GLFWwindow *window, bool edited = true);
void macosGetKey(Keys key, int *output);
}
#endif

View File

@@ -38,7 +38,7 @@ namespace hex::prv {
[[nodiscard]] std::string getName() const override { return m_name; }
[[nodiscard]] std::string getTypeName() const override { return "MemoryProvider"; }
[[nodiscard]] UnlocalizedString getTypeName() const override { return "MemoryProvider"; }
private:
void renameFile();

View File

@@ -30,6 +30,7 @@ namespace hex::prv {
struct MenuEntry {
std::string name;
const char *icon;
std::function<void()> callback;
};
@@ -151,7 +152,7 @@ namespace hex::prv {
* like "hex.builtin.provider.mem_file" or "hex.builtin.provider.file"
* @return The provider's type name
*/
[[nodiscard]] virtual std::string getTypeName() const = 0;
[[nodiscard]] virtual UnlocalizedString getTypeName() const = 0;
/**
* @brief Gets a human readable representation of the current provider

View File

@@ -1,7 +1,10 @@
#pragma once
#include <hex/api/imhex_api.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/api/events/events_provider.hpp>
#include <hex/api/events/events_lifecycle.hpp>
#include <hex/api/events/requests_provider.hpp>
#include <map>
#include <ranges>

View File

@@ -2,7 +2,7 @@
#include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/api/events/events_interaction.hpp>
#include <hex/providers/undo_redo/operations/operation.hpp>

View File

@@ -47,7 +47,7 @@ namespace hex::test {
return m_data->size();
}
[[nodiscard]] std::string getTypeName() const override { return "hex.test.provider.test"; }
[[nodiscard]] UnlocalizedString getTypeName() const override { return "hex.test.provider.test"; }
bool open() override { return true; }
void close() override { }

View File

@@ -0,0 +1,57 @@
#pragma once
#include <hex.hpp>
#include <imgui.h>
#include <imgui_internal.h>
#include <hex/helpers/utils.hpp>
#include <list>
#include <memory>
#include <mutex>
#include "hex/api/localization_manager.hpp"
namespace hex {
namespace impl {
class BannerBase {
public:
BannerBase(ImColor color) : m_color(color) {}
virtual ~BannerBase() = default;
virtual void draw() { drawContent(); }
virtual void drawContent() = 0;
[[nodiscard]] static std::list<std::unique_ptr<BannerBase>> &getOpenBanners();
[[nodiscard]] const ImColor& getColor() const {
return m_color;
}
void close() { m_shouldClose = true; }
[[nodiscard]] bool shouldClose() const { return m_shouldClose; }
protected:
static std::mutex& getMutex();
bool m_shouldClose = false;
ImColor m_color;
};
}
template<typename T>
class Banner : public impl::BannerBase {
public:
using impl::BannerBase::BannerBase;
template<typename ...Args>
static void open(Args && ... args) {
std::lock_guard lock(getMutex());
auto toast = std::make_unique<T>(std::forward<Args>(args)...);
getOpenBanners().emplace_back(std::move(toast));
}
};
}

View File

@@ -79,16 +79,16 @@ namespace ImGuiExt {
Texture(const Texture&) = delete;
Texture(Texture&& other) noexcept;
static Texture fromImage(const ImU8 *buffer, int size, Filter filter = Filter::Nearest);
static Texture fromImage(std::span<const std::byte> buffer, Filter filter = Filter::Nearest);
static Texture fromImage(const char *path, Filter filter = Filter::Nearest);
static Texture fromImage(const std::fs::path &path, Filter filter = Filter::Nearest);
static Texture fromGLTexture(unsigned int texture, int width, int height);
static Texture fromBitmap(const ImU8 *buffer, int size, int width, int height, Filter filter = Filter::Nearest);
static Texture fromBitmap(std::span<const std::byte> buffer, int width, int height, Filter filter = Filter::Nearest);
static Texture fromSVG(const char *path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
static Texture fromSVG(const std::fs::path &path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
static Texture fromSVG(std::span<const std::byte> buffer, int width = 0, int height = 0, Filter filter = Filter::Nearest);
[[nodiscard]] static Texture fromImage(const ImU8 *buffer, int size, Filter filter = Filter::Nearest);
[[nodiscard]] static Texture fromImage(std::span<const std::byte> buffer, Filter filter = Filter::Nearest);
[[nodiscard]] static Texture fromImage(const char *path, Filter filter = Filter::Nearest);
[[nodiscard]] static Texture fromImage(const std::fs::path &path, Filter filter = Filter::Nearest);
[[nodiscard]] static Texture fromGLTexture(unsigned int texture, int width, int height);
[[nodiscard]] static Texture fromBitmap(const ImU8 *buffer, int size, int width, int height, Filter filter = Filter::Nearest);
[[nodiscard]] static Texture fromBitmap(std::span<const std::byte> buffer, int width, int height, Filter filter = Filter::Nearest);
[[nodiscard]] static Texture fromSVG(const char *path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
[[nodiscard]] static Texture fromSVG(const std::fs::path &path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
[[nodiscard]] static Texture fromSVG(std::span<const std::byte> buffer, int width = 0, int height = 0, Filter filter = Filter::Nearest);
~Texture();
@@ -144,13 +144,13 @@ namespace ImGuiExt {
bool TitleBarButton(const char *label, ImVec2 size_arg);
bool ToolBarButton(const char *symbol, ImVec4 color);
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0), ImVec2 iconOffset = ImVec2(0, 0));
bool InputIntegerPrefix(const char* label, const char *prefix, void *value, ImGuiDataType type, const char *format, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool SliderBytes(const char *label, u64 *value, u64 min, u64 max, ImGuiSliderFlags flags = ImGuiSliderFlags_None);
bool SliderBytes(const char *label, u64 *value, u64 min, u64 max, u64 stepSize = 1, ImGuiSliderFlags flags = ImGuiSliderFlags_None);
inline bool HasSecondPassed() {
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
@@ -203,7 +203,7 @@ namespace ImGuiExt {
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
ImGui::PushItemWidth(ImGui::CalcTextSize(text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2);
ImGui::InputText("##", const_cast<char *>(text.c_str()), text.size(), ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoHorizontalScroll);
ImGui::InputText("##", const_cast<char *>(text.c_str()), text.size() + 1, ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoHorizontalScroll);
ImGui::PopItemWidth();
ImGui::PopStyleColor();
@@ -235,11 +235,13 @@ namespace ImGuiExt {
inline void TextFormattedWrappedSelectable(std::string_view fmt, auto &&...args) {
// Manually wrap text, using the letter M (generally the widest character in non-monospaced fonts) to calculate the character width to use.
auto text = wolv::util::wrapMonospacedString(
auto text = wolv::util::trim(wolv::util::wrapMonospacedString(
hex::format(fmt, std::forward<decltype(args)>(args)...),
ImGui::CalcTextSize("M").x,
ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ScrollbarSize - ImGui::GetStyle().FrameBorderSize
);
));
auto textSize = ImGui::CalcTextSize(text.c_str());
ImGui::PushID(text.c_str());
@@ -250,8 +252,8 @@ namespace ImGuiExt {
ImGui::InputTextMultiline(
"##",
const_cast<char *>(text.c_str()),
text.size(),
ImVec2(0, -FLT_MIN),
text.size() + 1,
ImVec2(0, textSize.y),
ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoHorizontalScroll
);
ImGui::PopItemWidth();
@@ -291,8 +293,8 @@ namespace ImGuiExt {
bool BitCheckbox(const char* label, bool* v);
bool DimmedButton(const char* label, ImVec2 size = ImVec2(0, 0));
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size = ImVec2(0, 0));
bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size);
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size = ImVec2(0, 0), ImVec2 iconOffset = ImVec2(0, 0));
bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size = ImVec2(0, 0), ImVec2 iconOffset = ImVec2(0, 0));
bool DimmedIconToggle(const char *icon, bool *v);
bool DimmedIconToggle(const char *iconOn, const char *iconOff, bool *v);

View File

@@ -8,7 +8,6 @@
#include <hex/api/imhex_api.hpp>
#include <hex/api/shortcut_manager.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/providers/provider.hpp>

View File

@@ -1,11 +1,15 @@
#include <hex/api/achievement_manager.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/api/events/events_interaction.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/default_paths.hpp>
#include <nlohmann/json.hpp>
#if defined(OS_WEB)
#include <emscripten.h>
#endif
namespace hex {
static AutoReset<std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>>> s_achievements;
@@ -215,7 +219,16 @@ namespace hex {
}
try {
auto json = nlohmann::json::parse(file.readString());
#if defined(OS_WEB)
auto data = (char *) MAIN_THREAD_EM_ASM_INT({
let data = localStorage.getItem("achievements");
return data ? stringToNewUTF8(data) : null;
});
#else
auto data = file.readString();
#endif
auto json = nlohmann::json::parse(data);
for (const auto &[categoryName, achievements] : getAchievements()) {
for (const auto &[achievementName, achievement] : achievements) {
@@ -254,16 +267,23 @@ namespace hex {
if (json.empty())
return;
for (const auto &directory : paths::Config.write()) {
auto path = directory / AchievementsFile;
#if defined(OS_WEB)
auto data = json.dump();
MAIN_THREAD_EM_ASM({
localStorage.setItem("achievements", UTF8ToString($0));
}, data.c_str());
#else
for (const auto &directory : paths::Config.write()) {
auto path = directory / AchievementsFile;
wolv::io::File file(path, wolv::io::File::Mode::Create);
if (!file.isValid())
continue;
wolv::io::File file(path, wolv::io::File::Mode::Create);
if (!file.isValid())
continue;
file.writeString(json.dump(4));
break;
}
file.writeString(json.dump(4));
break;
}
#endif
}
}

View File

@@ -1,5 +1,6 @@
#include <hex/api/content_registry.hpp>
#include <hex/api/shortcut_manager.hpp>
#include <hex/api/events/requests_provider.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
@@ -38,6 +39,34 @@ namespace hex {
static AutoReset<std::map<std::string, std::map<std::string, std::vector<OnChange>>>> s_onChangeCallbacks;
static void runAllOnChangeCallbacks() {
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
for (const auto &[name, callbacks] : rest) {
for (const auto &[id, callback] : callbacks) {
try {
callback(getSetting(category, name, {}));
} catch (const std::exception &e) {
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
}
}
}
}
}
void runOnChangeHandlers(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &value) {
if (auto categoryIt = s_onChangeCallbacks->find(unlocalizedCategory); categoryIt != s_onChangeCallbacks->end()) {
if (auto nameIt = categoryIt->second.find(unlocalizedName); nameIt != categoryIt->second.end()) {
for (const auto &[id, callback] : nameIt->second) {
try {
callback(value);
} catch (const nlohmann::json::exception &e) {
log::error("Failed to run onChange handler for setting {}/{}: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
}
}
}
}
}
static AutoReset<nlohmann::json> s_settings;
const nlohmann::json& getSettingsData() {
return s_settings;
@@ -72,24 +101,28 @@ namespace hex {
s_settings = nlohmann::json::parse(data);
}
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
for (const auto &[name, callbacks] : rest) {
for (const auto &[id, callback] : callbacks) {
try {
callback(getSetting(category, name, {}));
} catch (const std::exception &e) {
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
}
}
}
}
runAllOnChangeCallbacks();
}
void store() {
auto data = s_settings->dump();
if (!s_settings.isValid())
return;
const auto &settingsData = *s_settings;
// During a crash settings can be empty, causing them to be overwritten.
if (settingsData.empty()) {
return;
}
const auto result = settingsData.dump(4);
if (result.empty()) {
return;
}
MAIN_THREAD_EM_ASM({
localStorage.setItem("config", UTF8ToString($0));
}, data.c_str());
}, result.c_str());
}
void clear() {
@@ -115,17 +148,7 @@ namespace hex {
if (!loaded)
store();
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
for (const auto &[name, callbacks] : rest) {
for (const auto &[id, callback] : callbacks) {
try {
callback(getSetting(category, name, {}));
} catch (const std::exception &e) {
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
}
}
}
}
runAllOnChangeCallbacks();
}
void store() {
@@ -135,7 +158,7 @@ namespace hex {
const auto &settingsData = *s_settings;
// During a crash settings can be empty, causing them to be overwritten.
if (settingsData.empty()) {
if (s_settings->empty()) {
return;
}
@@ -201,6 +224,8 @@ namespace hex {
log::error("Failed to load setting [{} / {}]: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
}
});
runOnChangeHandlers(unlocalizedCategory, unlocalizedName, getSetting(unlocalizedCategory, unlocalizedName, entry->widget->store()));
}
return entry->widget.get();
@@ -210,20 +235,6 @@ namespace hex {
hex::log::error("Failed to read setting {}/{}: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
}
void runOnChangeHandlers(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &value) {
if (auto categoryIt = s_onChangeCallbacks->find(unlocalizedCategory); categoryIt != s_onChangeCallbacks->end()) {
if (auto nameIt = categoryIt->second.find(unlocalizedName); nameIt != categoryIt->second.end()) {
for (const auto &[id, callback] : nameIt->second) {
try {
callback(value);
} catch (const nlohmann::json::exception &e) {
log::error("Failed to run onChange handler for setting {}/{}: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
}
}
}
}
}
}
void setCategoryDescription(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedDescription) {
@@ -325,7 +336,7 @@ namespace hex {
bool SliderDataSize::draw(const std::string &name) {
return ImGuiExt::SliderBytes(name.c_str(), &m_value, m_min, m_max);
return ImGuiExt::SliderBytes(name.c_str(), &m_value, m_min, m_max, m_stepSize);
}
void SliderDataSize::load(const nlohmann::json &data) {
@@ -341,17 +352,34 @@ namespace hex {
}
ColorPicker::ColorPicker(ImColor defaultColor) {
m_value = {
defaultColor.Value.x,
defaultColor.Value.y,
defaultColor.Value.z,
defaultColor.Value.w
ColorPicker::ColorPicker(ImColor defaultColor, ImGuiColorEditFlags flags) {
m_defaultValue = m_value = {
defaultColor.Value.x,
defaultColor.Value.y,
defaultColor.Value.z,
defaultColor.Value.w
};
m_flags = flags;
}
bool ColorPicker::draw(const std::string &name) {
return ImGui::ColorEdit4(name.c_str(), m_value.data(), ImGuiColorEditFlags_NoInputs);
ImGui::PushID(name.c_str());
auto result = ImGui::ColorEdit4("##color_picker", m_value.data(), ImGuiColorEditFlags_NoInputs | m_flags);
ImGui::SameLine();
if (ImGui::Button("X", ImGui::GetStyle().FramePadding * 2 + ImVec2(ImGui::GetTextLineHeight(), ImGui::GetTextLineHeight()))) {
m_value = m_defaultValue;
result = true;
}
ImGui::SameLine();
ImGui::TextUnformatted(name.c_str());
ImGui::PopID();
return result;
}
void ColorPicker::load(const nlohmann::json &data) {
@@ -377,7 +405,7 @@ namespace hex {
bool DropDown::draw(const std::string &name) {
auto preview = "";
if (static_cast<size_t>(m_value) < m_items.size())
preview = m_items[m_value].c_str();
preview = m_items[m_value].get().c_str();
bool changed = false;
if (ImGui::BeginCombo(name.c_str(), Lang(preview))) {
@@ -630,7 +658,7 @@ namespace hex {
}
runtime.addDefine("__IMHEX__");
runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion());
runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion().get());
}
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
@@ -752,6 +780,14 @@ namespace hex {
impl::s_entries->push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
}
void drawMenuItems(const std::function<void()> &function) {
if (ImGui::BeginPopup("##DataInspectorRowContextMenu")) {
function();
ImGui::Separator();
ImGui::EndPopup();
}
}
}
namespace ContentRegistry::DataProcessorNode {
@@ -917,17 +953,10 @@ namespace hex {
});
if (shortcut != Shortcut::None) {
auto callbackIfEnabled = [enabledCallback, function]{ if (enabledCallback()) { function(); } };
const auto unlocalizedShortcutName =
unlocalizedMainMenuNames.size() == 1 ?
std::vector { unlocalizedMainMenuNames.back() } :
std::vector(unlocalizedMainMenuNames.begin() + 1, unlocalizedMainMenuNames.end());
if (shortcut.isLocal() && view != nullptr)
ShortcutManager::addShortcut(view, shortcut, unlocalizedShortcutName, callbackIfEnabled);
ShortcutManager::addShortcut(view, shortcut, unlocalizedMainMenuNames, function, enabledCallback);
else
ShortcutManager::addGlobalShortcut(shortcut, unlocalizedShortcutName, callbackIfEnabled);
ShortcutManager::addGlobalShortcut(shortcut, unlocalizedMainMenuNames, function, enabledCallback);
}
}
@@ -1391,4 +1420,23 @@ namespace hex {
}
namespace ContentRegistry::Disassembler {
namespace impl {
static AutoReset<std::map<std::string, impl::CreatorFunction>> s_architectures;
void addArchitectureCreator(impl::CreatorFunction function) {
const auto arch = function();
(*s_architectures)[arch->getName()] = std::move(function);
}
const std::map<std::string, impl::CreatorFunction>& getArchitectures() {
return *s_architectures;
}
}
}
}

View File

@@ -1,6 +1,13 @@
#include <hex/api/imhex_api.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/api/events/events_provider.hpp>
#include <hex/api/events/events_lifecycle.hpp>
#include <hex/api/events/events_gui.hpp>
#include <hex/api/events/requests_interaction.hpp>
#include <hex/api/events/requests_lifecycle.hpp>
#include <hex/api/events/requests_provider.hpp>
#include <hex/api/events/requests_gui.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/utils.hpp>
@@ -11,6 +18,7 @@
#include <wolv/utils/string.hpp>
#include <utility>
#include <numeric>
#include <imgui.h>
#include <imgui_internal.h>
@@ -18,13 +26,20 @@
#include <algorithm>
#include <GLFW/glfw3.h>
#include <hex/helpers/utils_macos.hpp>
#if defined(OS_WINDOWS)
#include <windows.h>
#include <DSRole.h>
#else
#include <sys/utsname.h>
#include <unistd.h>
#endif
#if defined(OS_WEB)
#include <emscripten.h>
#endif
namespace hex {
@@ -608,6 +623,27 @@ namespace hex {
return impl::s_nativeScale;
}
float getBackingScaleFactor() {
#if defined(OS_WINDOWS)
return 1.0F;
#elif defined(OS_MACOS)
return ::getBackingScaleFactor();
#elif defined(OS_LINUX)
if (std::string_view(::getenv("XDG_SESSION_TYPE")) == "x11")
return 1.0F;
else {
float xScale = 0, yScale = 0;
glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xScale, &yScale);
return std::midpoint(xScale, yScale);
}
#elif defined(OS_WEB)
return 1.0F;
#else
return 1.0F;
#endif
}
ImVec2 getMainWindowPosition() {
if ((ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) != ImGuiConfigFlags_None)
@@ -645,6 +681,14 @@ namespace hex {
return hex::getContainingModule(reinterpret_cast<void*>(&getLibImHexModuleHandle));
}
void addMigrationRoutine(SemanticVersion migrationVersion, std::function<void()> function) {
EventImHexUpdated::subscribe([migrationVersion, function](const SemanticVersion &oldVersion, const SemanticVersion &newVersion) {
if (oldVersion < migrationVersion && newVersion >= migrationVersion) {
function();
}
});
}
const std::map<std::string, std::string>& getInitArguments() {
return *impl::s_initArguments;
@@ -689,6 +733,27 @@ namespace hex {
return impl::s_glRenderer;
}
bool isCorporateEnvironment() {
#if defined(OS_WINDOWS)
{
DSROLE_PRIMARY_DOMAIN_INFO_BASIC * info;
if ((DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *)&info) == ERROR_SUCCESS) && (info != nullptr))
{
bool result = std::wstring(info->DomainNameFlat).empty();
DsRoleFreeMemory(info);
return result;
} else {
DWORD size = 1024;
::GetComputerNameExA(ComputerNameDnsDomain, nullptr, &size);
return size > 0;
}
}
#else
return false;
#endif
}
bool isPortableVersion() {
static std::optional<bool> portable;
if (portable.has_value())
@@ -794,16 +859,11 @@ namespace hex {
return { { name, version } };
}
std::string getImHexVersion(bool withBuildType) {
SemanticVersion getImHexVersion() {
#if defined IMHEX_VERSION
if (withBuildType) {
return IMHEX_VERSION;
} else {
auto version = std::string(IMHEX_VERSION);
return version.substr(0, version.find('-'));
}
return SemanticVersion(IMHEX_VERSION);
#else
return "Unknown";
return {};
#endif
}
@@ -837,7 +897,7 @@ namespace hex {
}
bool isNightlyBuild() {
return getImHexVersion(false).ends_with("WIP");
return getImHexVersion().nightly();
}
bool updateImHex(UpdateType updateType) {
@@ -935,11 +995,6 @@ namespace hex {
return *s_fonts;
}
static AutoReset<std::fs::path> s_customFontPath;
void setCustomFontPath(const std::fs::path &path) {
s_customFontPath = path;
}
static float s_fontSize = DefaultFontSize;
void setFontSize(float size) {
s_fontSize = size;
@@ -957,6 +1012,10 @@ namespace hex {
s_italicFont = italic;
}
static AutoReset<std::map<UnlocalizedString, ImFont*>> s_fontDefinitions;
std::map<UnlocalizedString, ImFont*>& getFontDefinitions() {
return *s_fontDefinitions;
}
}
@@ -1021,10 +1080,6 @@ namespace hex {
});
}
const std::fs::path& getCustomFontPath() {
return impl::s_customFontPath;
}
float getFontSize() {
return impl::s_fontSize;
}
@@ -1033,6 +1088,14 @@ namespace hex {
return impl::s_fontAtlas;
}
void registerFont(const UnlocalizedString &fontName) {
(*impl::s_fontDefinitions)[fontName] = nullptr;
}
ImFont* getFont(const UnlocalizedString &fontName) {
return (*impl::s_fontDefinitions)[fontName];
}
ImFont* Bold() {
return impl::s_boldFont;
}

View File

@@ -56,18 +56,19 @@ namespace hex {
}
}
void loadLanguage(const std::string &language) {
void loadLanguage(std::string language) {
auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions();
const auto& fallbackLanguage = getFallbackLanguage();
if (!definitions.contains(language))
return;
language = fallbackLanguage;
s_currStrings->clear();
loadLanguageDefinitions(definitions.at(language));
const auto& fallbackLanguage = getFallbackLanguage();
loadLanguageDefinitions(definitions.at(fallbackLanguage));
if (language != fallbackLanguage)
loadLanguageDefinitions(definitions.at(fallbackLanguage));
s_selectedLanguage = language;
}

View File

@@ -129,7 +129,7 @@ namespace hex {
const auto requestedVersion = getCompatibleVersion();
const auto imhexVersion = ImHexApi::System::getImHexVersion();
const auto imhexVersion = ImHexApi::System::getImHexVersion().get();
if (!imhexVersion.starts_with(requestedVersion)) {
if (requestedVersion.empty()) {
log::warn("Plugin '{}' did not specify a compatible version, assuming it is compatible with the current version of ImHex.", wolv::util::toUTF8String(m_path.filename()));

View File

@@ -1,6 +1,7 @@
#include <hex/api/shortcut_manager.hpp>
#include <imgui.h>
#include <hex/api/content_registry.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <hex/ui/view.hpp>
@@ -12,6 +13,8 @@ namespace hex {
AutoReset<std::map<Shortcut, ShortcutManager::ShortcutEntry>> s_globalShortcuts;
std::atomic<bool> s_paused;
std::optional<Shortcut> s_prevShortcut;
bool s_macOSMode = false;
AutoReset<std::optional<UnlocalizedString>> s_lastShortcutMainMenu;
}
@@ -78,22 +81,14 @@ namespace hex {
std::string Shortcut::toString() const {
std::string result;
#if defined(OS_MACOS)
constexpr static auto CTRL_NAME = "";
constexpr static auto ALT_NAME = "";
constexpr static auto SHIFT_NAME = "";
constexpr static auto SUPER_NAME = "";
constexpr static auto Concatination = " ";
#else
constexpr static auto CTRL_NAME = "CTRL";
constexpr static auto ALT_NAME = "ALT";
constexpr static auto SHIFT_NAME = "SHIFT";
constexpr static auto SUPER_NAME = "SUPER";
constexpr static auto Concatination = " + ";
#endif
const auto CTRL_NAME = s_macOSMode ? "" : "CTRL";
const auto ALT_NAME = s_macOSMode ? "" : "ALT";
const auto SHIFT_NAME = s_macOSMode ? "" : "SHIFT";
const auto SUPER_NAME = s_macOSMode ? "" : "SUPER";
const auto Concatination = s_macOSMode ? " " : " + ";
auto keys = m_keys;
if (keys.erase(CTRL) > 0) {
if (keys.erase(CTRL) > 0 || (!s_macOSMode && keys.erase(CTRLCMD) > 0)) {
result += CTRL_NAME;
result += Concatination;
}
@@ -105,7 +100,7 @@ namespace hex {
result += SHIFT_NAME;
result += Concatination;
}
if (keys.erase(SUPER) > 0) {
if (keys.erase(SUPER) > 0 || (s_macOSMode && keys.erase(CTRLCMD) > 0)) {
result += SUPER_NAME;
result += Concatination;
}
@@ -238,28 +233,66 @@ namespace hex {
return result;
}
KeyEquivalent Shortcut::toKeyEquivalent() const {
#if defined(OS_MACOS)
if (*this == None)
return { };
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback) {
KeyEquivalent result = {};
result.valid = true;
for (const auto &key : m_keys) {
switch (key.getKeyCode()) {
case CTRL.getKeyCode():
result.ctrl = true;
break;
case SHIFT.getKeyCode():
result.shift = true;
break;
case ALT.getKeyCode():
result.opt = true;
break;
case SUPER.getKeyCode():
case CTRLCMD.getKeyCode():
result.cmd = true;
break;
case CurrentView.getKeyCode(): break;
case AllowWhileTyping.getKeyCode(): break;
default:
macosGetKey(Keys(key.getKeyCode()), &result.key);
break;
}
}
return result;
#else
return { };
#endif
}
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback, const EnabledCallback &enabledCallback) {
log::debug("Adding global shortcut {} for {}", shortcut.toString(), unlocalizedName.back().get());
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { shortcut, unlocalizedName, callback } });
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { shortcut, unlocalizedName, callback, enabledCallback } });
if (!inserted) log::error("Failed to add shortcut!");
}
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback, const EnabledCallback &enabledCallback) {
log::debug("Adding global shortcut {} for {}", shortcut.toString(), unlocalizedName.get());
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { shortcut, { unlocalizedName }, callback } });
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { shortcut, { unlocalizedName }, callback, enabledCallback } });
if (!inserted) log::error("Failed to add shortcut!");
}
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback) {
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback, const EnabledCallback &enabledCallback) {
log::debug("Adding shortcut {} for {}", shortcut.toString(), unlocalizedName.back().get());
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, unlocalizedName, callback } });
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, unlocalizedName, callback, enabledCallback } });
if (!inserted) log::error("Failed to add shortcut!");
}
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback, const EnabledCallback &enabledCallback) {
log::debug("Adding shortcut {} for {}", shortcut.toString(), unlocalizedName.get());
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, { unlocalizedName }, callback } });
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, { unlocalizedName }, callback, enabledCallback } });
if (!inserted) log::error("Failed to add shortcut!");
}
@@ -267,32 +300,45 @@ namespace hex {
Shortcut pressedShortcut;
if (ctrl)
pressedShortcut += CTRL;
pressedShortcut += s_macOSMode ? CTRL : CTRLCMD;
if (alt)
pressedShortcut += ALT;
if (shift)
pressedShortcut += SHIFT;
if (super)
pressedShortcut += SUPER;
pressedShortcut += s_macOSMode ? CTRLCMD : SUPER;
if (focused)
pressedShortcut += CurrentView;
if (ImGui::GetIO().WantTextInput)
pressedShortcut += AllowWhileTyping;
pressedShortcut += static_cast<Keys>(keyCode);
return pressedShortcut;
}
static void processShortcut(const Shortcut &shortcut, const std::map<Shortcut, ShortcutManager::ShortcutEntry> &shortcuts) {
static void processShortcut(Shortcut shortcut, const std::map<Shortcut, ShortcutManager::ShortcutEntry> &shortcuts) {
if (s_paused) return;
if (ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId))
return;
if (auto it = shortcuts.find(shortcut); it != shortcuts.end()) {
const bool currentlyTyping = ImGui::GetIO().WantTextInput;
auto it = shortcuts.find(shortcut + AllowWhileTyping);
if (!currentlyTyping && it == shortcuts.end()) {
if (it == shortcuts.end())
it = shortcuts.find(shortcut);
}
if (it != shortcuts.end()) {
const auto &[foundShortcut, entry] = *it;
entry.callback();
if (entry.enabledCallback()) {
entry.callback();
if (!entry.unlocalizedName.empty()) {
s_lastShortcutMainMenu = entry.unlocalizedName.front();
}
}
}
}
@@ -312,6 +358,15 @@ namespace hex {
processShortcut(pressedShortcut, s_globalShortcuts);
}
std::optional<UnlocalizedString> ShortcutManager::getLastActivatedMenu() {
return *s_lastShortcutMainMenu;
}
void ShortcutManager::resetLastActivatedMenu() {
s_lastShortcutMainMenu->reset();
}
void ShortcutManager::clearShortcuts() {
s_globalShortcuts->clear();
}
@@ -387,4 +442,9 @@ namespace hex {
return result;
}
void ShortcutManager::enableMacOSMode() {
s_macOSMode = true;
}
}

View File

@@ -1,5 +1,5 @@
#include <hex/api/theme_manager.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/api/events/events_interaction.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
@@ -16,6 +16,7 @@ namespace hex {
AutoReset<std::map<std::string, ThemeManager::StyleHandler>> s_styleHandlers;
AutoReset<std::string> s_imageTheme;
AutoReset<std::string> s_currTheme;
AutoReset<std::optional<float>> s_accentColor;
std::recursive_mutex s_themeMutex;
}
@@ -155,12 +156,28 @@ namespace hex {
continue;
}
auto color = parseColorString(value.get<std::string>());
auto colorString = value.get<std::string>();
bool accentableColor = false;
if (colorString.starts_with("*")) {
colorString = colorString.substr(1);
accentableColor = true;
}
auto color = parseColorString(colorString);
if (!color.has_value()) {
log::warn("Invalid color '{}' for '{}.{}'", value.get<std::string>(), type, key);
log::warn("Invalid color '{}' for '{}.{}'", colorString, type, key);
continue;
}
if (accentableColor && s_accentColor->has_value()) {
float h, s, v;
ImGui::ColorConvertRGBtoHSV(color->Value.x, color->Value.y, color->Value.z, h, s, v);
h = s_accentColor->value();
ImGui::ColorConvertHSVtoRGB(h, s, v, color->Value.x, color->Value.y, color->Value.z);
}
(*s_themeHandlers)[type].setFunction((*s_themeHandlers)[type].colorMap.at(key), color.value());
}
}
@@ -236,6 +253,14 @@ namespace hex {
s_currTheme->clear();
}
void ThemeManager::setAccentColor(const ImColor &color) {
float h, s, v;
ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, h, s, v);
s_accentColor = h;
reapplyCurrentTheme();
}
const std::map<std::string, ThemeManager::ThemeHandler> &ThemeManager::getThemeHandlers() {
return s_themeHandlers;

View File

@@ -2,6 +2,7 @@
#include <hex/api/imhex_api.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/api/events/events_gui.hpp>
#include <hex/helpers/auto_reset.hpp>
@@ -11,6 +12,8 @@
#include <map>
#include <imgui.h>
namespace hex {
namespace {
@@ -20,10 +23,12 @@ namespace hex {
AutoReset<std::map<ImGuiID, std::string>> s_highlights;
AutoReset<std::vector<std::pair<ImRect, std::string>>> s_highlightDisplays;
AutoReset<std::map<ImGuiID, ImRect>> s_interactiveHelpDisplays;
AutoReset<std::map<ImGuiID, std::function<void()>>> s_interactiveHelpItems;
ImRect s_hoveredRect;
ImGuiID s_hoveredId;
ImGuiID s_activeHelpId;
bool s_helpHoverActive = false;
@@ -33,6 +38,13 @@ namespace hex {
idStack.push_back(0);
}
void add(const char *string) {
const ImGuiID seed = idStack.back();
const ImGuiID id = ImHashStr(string, 0, seed);
idStack.push_back(id);
}
void add(const std::string &string) {
const ImGuiID seed = idStack.back();
const ImGuiID id = ImHashStr(string.c_str(), string.length(), seed);
@@ -84,9 +96,23 @@ namespace hex {
EventImGuiElementRendered::subscribe([](ImGuiID id, const std::array<float, 4> bb){
const auto boundingBox = ImRect(bb[0], bb[1], bb[2], bb[3]);
const auto element = hex::s_highlights->find(id);
if (element != hex::s_highlights->end()) {
hex::s_highlightDisplays->emplace_back(boundingBox, element->second);
{
const auto element = hex::s_highlights->find(id);
if (element != hex::s_highlights->end()) {
hex::s_highlightDisplays->emplace_back(boundingBox, element->second);
const auto window = ImGui::GetCurrentWindow();
if (window != nullptr && window->DockNode != nullptr && window->DockNode->TabBar != nullptr)
window->DockNode->TabBar->NextSelectedTabId = window->TabId;
}
}
{
const auto element = s_interactiveHelpItems->find(id);
if (element != s_interactiveHelpItems->end()) {
(*s_interactiveHelpDisplays)[id] = boundingBox;
}
}
if (id != 0 && boundingBox.Contains(ImGui::GetMousePos())) {
@@ -117,10 +143,10 @@ namespace hex {
});
}
void TutorialManager::addInteractiveHelpText(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, UnlocalizedString text) {
void TutorialManager::addInteractiveHelpText(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, UnlocalizedString unlocalizedString) {
auto id = calculateId(ids);
s_interactiveHelpItems->emplace(id, [text = std::move(text)]{
s_interactiveHelpItems->emplace(id, [text = std::move(unlocalizedString)]{
log::info("{}", Lang(text).get());
});
}
@@ -133,6 +159,39 @@ namespace hex {
});
}
void TutorialManager::setLastItemInteractiveHelpPopup(std::function<void()> callback) {
auto id = ImGui::GetItemID();
if (!s_interactiveHelpItems->contains(id)) {
s_interactiveHelpItems->emplace(id, [id]{
s_activeHelpId = id;
});
}
if (id == s_activeHelpId) {
ImGui::SetNextWindowSize(scaled({ 400, 0 }));
if (ImGui::BeginTooltip()) {
callback();
ImGui::EndTooltip();
}
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) || ImGui::IsKeyPressed(ImGuiKey_Escape))
s_activeHelpId = 0;
}
}
void TutorialManager::setLastItemInteractiveHelpLink(std::string link) {
auto id = ImGui::GetItemID();
if (s_interactiveHelpItems->contains(id))
return;
s_interactiveHelpItems->emplace(id, [link = std::move(link)]{
hex::openWebpage(link);
});
}
void TutorialManager::startTutorial(const UnlocalizedString &unlocalizedName) {
s_currentTutorial = s_tutorials->find(unlocalizedName);
if (s_currentTutorial == s_tutorials->end())
@@ -146,6 +205,19 @@ namespace hex {
const auto &drawList = ImGui::GetForegroundDrawList();
drawList->AddText(ImGui::GetMousePos() + scaled({ 10, -5, }), ImGui::GetColorU32(ImGuiCol_Text), "?");
for (const auto &[id, boundingBox] : *s_interactiveHelpDisplays) {
drawList->AddRect(
boundingBox.Min - ImVec2(5, 5),
boundingBox.Max + ImVec2(5, 5),
ImGui::GetColorU32(ImGuiCol_PlotHistogram),
5.0F,
ImDrawFlags_None,
2.0F
);
}
s_interactiveHelpDisplays->clear();
const bool mouseClicked = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
if (s_hoveredId != 0) {
drawList->AddRectFilled(s_hoveredRect.Min, s_hoveredRect.Max, 0x30FFFFFF);
@@ -164,6 +236,11 @@ namespace hex {
if (mouseClicked || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
s_helpHoverActive = false;
}
// Discard mouse click so it doesn't activate clicked item
ImGui::GetIO().MouseDown[ImGuiMouseButton_Left] = false;
ImGui::GetIO().MouseReleased[ImGuiMouseButton_Left] = false;
ImGui::GetIO().MouseClicked[ImGuiMouseButton_Left] = false;
}
for (const auto &[rect, unlocalizedText] : *s_highlightDisplays) {

View File

@@ -12,4 +12,13 @@ namespace hex::dbg {
}
static bool s_debugMode = false;
bool debugModeEnabled() {
return s_debugMode;
}
void setDebugModeEnabled(bool enabled) {
s_debugMode = enabled;
}
}

View File

@@ -123,7 +123,13 @@ namespace hex::fs {
// Call callback that will write the file
Module._fileBrowserCallback(stringToNewUTF8("/savedFiles/" + filename));
let data = FS.readFile("/savedFiles/" + filename);
let data;
try {
data = FS.readFile("/savedFiles/" + filename);
} catch (e) {
console.log(e);
return;
}
const reader = Object.assign(new FileReader(), {
onload: () => {
@@ -191,6 +197,7 @@ namespace hex::fs {
else if (!validExtensions.empty())
path = "file." + validExtensions[0].spec;
std::fs::create_directory("/savedFiles");
callJs_saveFile(path.filename().string().c_str());
break;
}

View File

@@ -1,4 +1,4 @@
#include <hex/api/event_manager.hpp>
#include <hex/api/events/events_gui.hpp>
#include <imgui.h>
#include <imgui_internal.h>

View File

@@ -1,7 +1,6 @@
#include <hex/helpers/logger.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/fmt.hpp>

View File

@@ -81,6 +81,9 @@ namespace hex::gl {
std::vector<char> log(512);
glGetShaderInfoLog(m_program, log.size(), nullptr, log.data());
log::error("Failed to link shader: {}", log.data());
glDeleteProgram(m_program);
m_program = 0;
}
}

View File

@@ -81,7 +81,7 @@ namespace hex {
return "";
}
[[nodiscard]] std::string getTypeName() const override { return ""; }
[[nodiscard]] UnlocalizedString getTypeName() const override { return ""; }
const std::map<u64, u8>& getPatches() const {
return m_patches;

View File

@@ -0,0 +1,118 @@
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/semantic_version.hpp>
#include <wolv/utils/string.hpp>
namespace hex {
SemanticVersion::SemanticVersion(const char *version) : SemanticVersion(std::string(version)) {
}
SemanticVersion::SemanticVersion(std::string_view version) : SemanticVersion(std::string(version.begin(), version.end())) {
}
SemanticVersion::SemanticVersion(std::string version) {
if (version.empty())
return;
if (version.starts_with("v"))
version = version.substr(1);
m_parts = wolv::util::splitString(version, ".");
if (m_parts.size() != 3 && m_parts.size() != 4) {
m_parts.clear();
return;
}
if (m_parts.back().contains("-")) {
auto buildTypeParts = wolv::util::splitString(m_parts.back(), "-");
if (buildTypeParts.size() != 2) {
m_parts.clear();
return;
}
m_parts.back() = buildTypeParts[0];
m_buildType = buildTypeParts[1];
}
}
u32 SemanticVersion::major() const {
if (!isValid()) return 0;
try {
return std::stoul(m_parts[0]);
} catch (...) {
return 0;
}
}
u32 SemanticVersion::minor() const {
if (!isValid()) return 0;
try {
return std::stoul(m_parts[1]);
} catch (...) {
return 0;
}
}
u32 SemanticVersion::patch() const {
if (!isValid()) return 0;
try {
return std::stoul(m_parts[2]);
} catch (...) {
return 0;
}
}
bool SemanticVersion::nightly() const {
if (!isValid()) return false;
return m_parts.size() == 4 && m_parts[3] == "WIP";
}
const std::string& SemanticVersion::buildType() const {
return m_buildType;
}
bool SemanticVersion::isValid() const {
return !m_parts.empty();
}
bool SemanticVersion::operator==(const SemanticVersion& other) const {
return this->m_parts == other.m_parts;
}
std::strong_ordering SemanticVersion::operator<=>(const SemanticVersion &other) const {
if (*this == other)
return std::strong_ordering::equivalent;
if (this->major() > other.major())
return std::strong_ordering::greater;
if (this->minor() > other.minor())
return std::strong_ordering::greater;
if (this->patch() > other.patch())
return std::strong_ordering::greater;
if (!this->nightly() && other.nightly())
return std::strong_ordering::greater;
return std::strong_ordering::less;
}
std::string SemanticVersion::get(bool withBuildType) const {
if (!isValid()) return "";
auto result = wolv::util::combineStrings(m_parts, ".");
if (withBuildType && !m_buildType.empty())
result += hex::format("-{}", m_buildType);
return result;
}
}

View File

@@ -8,6 +8,9 @@
#include <hex/providers/buffered_reader.hpp>
#include <imgui.h>
#include <imgui_internal.h>
#include <GLFW/glfw3.h>
#if defined(OS_WINDOWS)
#include <windows.h>
@@ -685,7 +688,7 @@ namespace hex {
return string;
// If the string is longer than the max length, find the last space before the max length
auto it = string.begin() + maxLength;
auto it = string.begin() + maxLength / 2;
while (it != string.begin() && !std::isspace(*it)) --it;
// If there's no space before the max length, just cut the string
@@ -844,4 +847,22 @@ namespace hex {
#endif
}
std::optional<ImColor> blendColors(const std::optional<ImColor> &a, const std::optional<ImColor> &b) {
if (!a.has_value() && !b.has_value())
return std::nullopt;
else if (a.has_value() && !b.has_value())
return a;
else if (!a.has_value() && b.has_value())
return b;
else
return ImAlphaBlendColors(a.value(), b.value());
}
extern "C" void macOSCloseButtonPressed() {
auto windowHandle = ImHexApi::System::getMainWindowHandle();
glfwHideWindow(windowHandle);
glfwIconifyWindow(windowHandle);
}
}

View File

@@ -18,6 +18,8 @@
#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>
#include <hex/helpers/keys.hpp>
void errorMessageMacos(const char *cMessage) {
CFStringRef strMessage = CFStringCreateWithCString(NULL, cMessage, kCFStringEncodingUTF8);
CFUserNotificationDisplayAlert(0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, strMessage, NULL, NULL, NULL, NULL, NULL);
@@ -46,6 +48,33 @@
return [[NSScreen mainScreen] backingScaleFactor];
}
void macOSCloseButtonPressed(void);
@interface CloseButtonHandler : NSObject
@end
@implementation CloseButtonHandler
- (void)pressed:(id)sender {
macOSCloseButtonPressed();
}
@end
@interface ImHexAppDelegate : NSObject<NSApplicationDelegate>
@end
@implementation ImHexAppDelegate
- (void) application:(NSApplication*)sender openFiles:(NSArray*)filenames
{
NSLog(@"A");
[NSApp replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
}
- (IBAction) clickAction:(id)sender {
NSLog(@"B");
}
@end
void setupMacosWindowStyle(GLFWwindow *window, bool borderlessWindowMode) {
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
@@ -59,6 +88,13 @@
[cocoaWindow setHasShadow:YES];
[cocoaWindow setBackgroundColor:[NSColor colorWithWhite: 0 alpha: 0.001f]];
}
NSButton *closeButton = [cocoaWindow standardWindowButton:NSWindowCloseButton];
[closeButton setAction:@selector(pressed:)];
[closeButton setTarget:[CloseButtonHandler alloc]];
NSApplication *app = [NSApplication sharedApplication];
[app setDelegate:[ImHexAppDelegate alloc]];
}
bool isMacosFullScreenModeEnabled(GLFWwindow *window) {
@@ -112,6 +148,12 @@
}
}
void macosSetWindowMovable(GLFWwindow *window, bool movable) {
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
[cocoaWindow setMovable:movable];
}
bool macosIsWindowBeingResizedByUser(GLFWwindow *window) {
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
@@ -145,4 +187,123 @@
@end
void macosGetKey(enum Keys key, int *output) {
*output = 0x00;
switch (key) {
case Space: *output = ' '; break;
case Apostrophe: *output = '\''; break;
case Comma: *output = ','; break;
case Minus: *output = '-'; break;
case Period: *output = '.'; break;
case Slash: *output = '/'; break;
case Num0: *output = '0'; break;
case Num1: *output = '1'; break;
case Num2: *output = '2'; break;
case Num3: *output = '3'; break;
case Num4: *output = '4'; break;
case Num5: *output = '5'; break;
case Num6: *output = '6'; break;
case Num7: *output = '7'; break;
case Num8: *output = '8'; break;
case Num9: *output = '9'; break;
case Semicolon: *output = ';'; break;
case Equals: *output = '='; break;
case A: *output = 'a'; break;
case B: *output = 'b'; break;
case C: *output = 'c'; break;
case D: *output = 'd'; break;
case E: *output = 'e'; break;
case F: *output = 'f'; break;
case G: *output = 'g'; break;
case H: *output = 'h'; break;
case I: *output = 'i'; break;
case J: *output = 'j'; break;
case K: *output = 'k'; break;
case L: *output = 'l'; break;
case M: *output = 'm'; break;
case N: *output = 'n'; break;
case O: *output = 'o'; break;
case P: *output = 'p'; break;
case Q: *output = 'q'; break;
case R: *output = 'r'; break;
case S: *output = 's'; break;
case T: *output = 't'; break;
case U: *output = 'u'; break;
case V: *output = 'v'; break;
case W: *output = 'w'; break;
case X: *output = 'x'; break;
case Y: *output = 'y'; break;
case Z: *output = 'z'; break;
case LeftBracket: *output = '/'; break;
case Backslash: *output = '\\'; break;
case RightBracket: *output = ']'; break;
case GraveAccent: *output = '`'; break;
case World1: break;
case World2: break;
case Escape: break;
case Enter: *output = NSEnterCharacter; break;
case Tab: *output = NSTabCharacter; break;
case Backspace: *output = NSBackspaceCharacter; break;
case Insert: *output = NSInsertFunctionKey; break;
case Delete: *output = NSDeleteCharacter; break;
case Right: *output = NSRightArrowFunctionKey; break;
case Left: *output = NSLeftArrowFunctionKey; break;
case Down: *output = NSDownArrowFunctionKey; break;
case Up: *output = NSUpArrowFunctionKey; break;
case PageUp: *output = NSPageUpFunctionKey; break;
case PageDown: *output = NSPageDownFunctionKey; break;
case Home: *output = NSHomeFunctionKey; break;
case End: *output = NSEndFunctionKey; break;
case CapsLock: break;
case ScrollLock: *output = NSScrollLockFunctionKey; break;
case NumLock: break;
case PrintScreen: *output = NSPrintScreenFunctionKey; break;
case Pause: *output = NSPauseFunctionKey; break;
case F1: *output = NSF1FunctionKey; break;
case F2: *output = NSF2FunctionKey; break;
case F3: *output = NSF3FunctionKey; break;
case F4: *output = NSF4FunctionKey; break;
case F5: *output = NSF5FunctionKey; break;
case F6: *output = NSF6FunctionKey; break;
case F7: *output = NSF7FunctionKey; break;
case F8: *output = NSF8FunctionKey; break;
case F9: *output = NSF9FunctionKey; break;
case F10: *output = NSF10FunctionKey; break;
case F11: *output = NSF11FunctionKey; break;
case F12: *output = NSF12FunctionKey; break;
case F13: *output = NSF13FunctionKey; break;
case F14: *output = NSF14FunctionKey; break;
case F15: *output = NSF15FunctionKey; break;
case F16: *output = NSF16FunctionKey; break;
case F17: *output = NSF17FunctionKey; break;
case F18: *output = NSF18FunctionKey; break;
case F19: *output = NSF19FunctionKey; break;
case F20: *output = NSF20FunctionKey; break;
case F21: *output = NSF21FunctionKey; break;
case F22: *output = NSF22FunctionKey; break;
case F23: *output = NSF23FunctionKey; break;
case F24: *output = NSF24FunctionKey; break;
case F25: *output = NSF25FunctionKey; break;
case KeyPad0: *output = '0'; break;
case KeyPad1: *output = '1'; break;
case KeyPad2: *output = '2'; break;
case KeyPad3: *output = '3'; break;
case KeyPad4: *output = '4'; break;
case KeyPad5: *output = '5'; break;
case KeyPad6: *output = '6'; break;
case KeyPad7: *output = '7'; break;
case KeyPad8: *output = '8'; break;
case KeyPad9: *output = '9'; break;
case KeyPadDecimal: *output = '.'; break;
case KeyPadDivide: *output = '/'; break;
case KeyPadMultiply: *output = '*'; break;
case KeyPadSubtract: *output = '-'; break;
case KeyPadAdd: *output = '+'; break;
case KeyPadEnter: *output = NSEnterCharacter; break;
case KeyPadEqual: *output = '='; break;
case Menu: *output = NSMenuFunctionKey; break;
default: break;
}
}
#endif

View File

@@ -1,7 +1,7 @@
#include <hex/providers/provider.hpp>
#include <hex.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/api/events/events_provider.hpp>
#include <cmath>
#include <cstring>

View File

@@ -4,7 +4,7 @@
#include "hex/subcommands/subcommands.hpp"
#include <hex/api/event_manager.hpp>
#include <hex/api/events/requests_lifecycle.hpp>
#include <hex/api/plugin_manager.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/helpers/logger.hpp>

View File

@@ -0,0 +1,18 @@
#include <hex/ui/banner.hpp>
#include <hex/helpers/auto_reset.hpp>
namespace hex::impl {
[[nodiscard]] std::list<std::unique_ptr<BannerBase>> &BannerBase::getOpenBanners() {
static AutoReset<std::list<std::unique_ptr<BannerBase>>> openBanners;
return openBanners;
}
std::mutex& BannerBase::getMutex() {
static std::mutex mutex;
return mutex;
}
}

View File

@@ -23,6 +23,7 @@
#include <hex/api/task_manager.hpp>
#include <hex/api/theme_manager.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils_macos.hpp>
namespace ImGuiExt {
@@ -222,14 +223,16 @@ namespace ImGuiExt {
}
Texture Texture::fromSVG(const char *path, int width, int height, Filter filter) {
const auto scaleFactor = hex::ImHexApi::System::getBackingScaleFactor();
auto document = lunasvg::Document::loadFromFile(path);
auto bitmap = document->renderToBitmap(width, height);
auto bitmap = document->renderToBitmap(width * scaleFactor, height * scaleFactor);
auto texture = createMultisampleTextureFromRGBA8Array(bitmap.data(), bitmap.width(), bitmap.height(), filter);
Texture result;
result.m_width = bitmap.width();
result.m_height = bitmap.height();
result.m_width = bitmap.width() / scaleFactor;
result.m_height = bitmap.height() / scaleFactor;
result.m_textureId = texture;
return result;
@@ -240,15 +243,17 @@ namespace ImGuiExt {
}
Texture Texture::fromSVG(std::span<const std::byte> buffer, int width, int height, Filter filter) {
const auto scaleFactor = hex::ImHexApi::System::getBackingScaleFactor();
auto document = lunasvg::Document::loadFromData(reinterpret_cast<const char*>(buffer.data()), buffer.size());
auto bitmap = document->renderToBitmap(width, height);
auto bitmap = document->renderToBitmap(width * scaleFactor, height * scaleFactor);
bitmap.convertToRGBA();
auto texture = createMultisampleTextureFromRGBA8Array(bitmap.data(), bitmap.width(), bitmap.height(), filter);
Texture result;
result.m_width = bitmap.width();
result.m_height = bitmap.height();
result.m_width = bitmap.width() / scaleFactor;
result.m_height = bitmap.height() / scaleFactor;
result.m_textureId = texture;
return result;
@@ -819,7 +824,7 @@ namespace ImGuiExt {
return pressed;
}
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg) {
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg, ImVec2 iconOffset) {
ImGuiWindow *window = GetCurrentWindow();
if (window->SkipItems)
return false;
@@ -850,7 +855,7 @@ namespace ImGuiExt {
: ImGuiCol_Button);
RenderNavCursor(bb, id);
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1.3, 1), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1.3, 1) + iconOffset, bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
PopStyleColor();
@@ -908,8 +913,9 @@ namespace ImGuiExt {
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U64, "%llX", flags | ImGuiInputTextFlags_CharsHexadecimal);
}
bool SliderBytes(const char *label, u64 *value, u64 min, u64 max, ImGuiSliderFlags flags) {
bool SliderBytes(const char *label, u64 *value, u64 min, u64 max, u64 stepSize, ImGuiSliderFlags flags) {
std::string format;
if (*value < 1024) {
format = hex::format("{} Bytes", *value);
} else if (*value < 1024 * 1024) {
@@ -920,7 +926,15 @@ namespace ImGuiExt {
format = hex::format("{:.2f} GB", *value / (1024.0 * 1024.0 * 1024.0));
}
return ImGui::SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format.c_str(), flags | ImGuiSliderFlags_Logarithmic);
*value /= stepSize;
min /= stepSize;
max /= stepSize;
auto result = ImGui::SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format.c_str(), flags | ImGuiSliderFlags_Logarithmic);
*value *= stepSize;
return result;
}
void SmallProgressBar(float fraction, float yOffset) {
@@ -1096,14 +1110,14 @@ namespace ImGuiExt {
return res;
}
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size){
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size, ImVec2 iconOffset) {
PushStyleColor(ImGuiCol_ButtonHovered, GetCustomColorU32(ImGuiCustomCol_DescButtonHovered));
PushStyleColor(ImGuiCol_Button, GetCustomColorU32(ImGuiCustomCol_DescButton));
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_ButtonActive));
PushStyleColor(ImGuiCol_ButtonActive, GetCustomColorU32(ImGuiCustomCol_DescButtonActive));
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
bool res = IconButton(symbol, color, size);
bool res = IconButton(symbol, color, size, iconOffset);
PopStyleColor(4);
PopStyleVar(1);
@@ -1111,7 +1125,7 @@ namespace ImGuiExt {
return res;
}
bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size) {
bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size, ImVec2 iconOffset) {
bool pushed = false;
bool toggled = false;
@@ -1120,7 +1134,7 @@ namespace ImGuiExt {
pushed = true;
}
if (DimmedIconButton(icon, GetStyleColorVec4(ImGuiCol_Text), size)) {
if (DimmedIconButton(icon, GetStyleColorVec4(ImGuiCol_Text), size, iconOffset)) {
*v = !*v;
toggled = true;
}

View File

@@ -10,7 +10,7 @@ add_subdirectory(cimgui)
add_subdirectory(implot)
add_subdirectory(implot3d)
add_subdirectory(imnodes)
add_subdirectory(custom)
add_subdirectory(backend)
add_subdirectory(ColorTextEditor)
set(IMGUI_LIBRARIES imgui_imgui imgui_cimgui imgui_implot imgui_implot3d imgui_imnodes imgui_custom imgui_color_text_editor PARENT_SCOPE)
set(IMGUI_LIBRARIES imgui_imgui imgui_cimgui imgui_implot imgui_implot3d imgui_imnodes imgui_backend imgui_color_text_editor PARENT_SCOPE)

View File

@@ -307,6 +307,7 @@ public:
return text.empty() || text == "\n";
}
void SetTopLine();
void SetScrollY();
void SetTextLines(const std::vector<std::string>& aLines);
std::vector<std::string> GetTextLines() const;
@@ -406,7 +407,7 @@ public:
void Cut();
void Paste();
void Delete();
int32_t GetPageSize() const;
float GetPageSize() const;
ImVec2 &GetCharAdvance() { return mCharAdvance; }
@@ -600,8 +601,8 @@ private:
float mLineNumberFieldWidth = 0.0F;
float mLongest = 0.0F;
float mTextStart = 20.0F; // position (in pixels) where a code line starts relative to the left of the TextEditor.
int mLeftMargin = 10;
int mTopLine = 0;
float mLeftMargin = 10.0;
float mTopLine = 0.0F;
bool mSetTopLine = false;
bool mCursorPositionChanged = false;
bool mBreakPointsChanged = false;
@@ -628,10 +629,11 @@ private:
uint64_t mStartTime = 0;
std::vector<std::string> mDefines;
TextEditor *mSourceCodeEditor = nullptr;
float mSavedScrollY = 0;
float mShiftedScrollY = 0;
float mScrollY = 0;
int mNumberOfLinesDisplayed = 0;
float mScrollYIncrement = 0.0F;
bool mSetScrollY = false;
float mNumberOfLinesDisplayed = 0;
float mLastClick = -1.0F;
bool mShowCursor = true;
bool mShowLineNumbers = true;

View File

@@ -311,6 +311,9 @@ TextEditor::Coordinates TextEditor::ScreenPosToCoordinates(const ImVec2 &aPositi
ImVec2 local(aPosition.x - origin.x, aPosition.y - origin.y);
int lineNo = std::max(0, (int)floor(local.y / mCharAdvance.y));
if (local.x < mCharAdvance.x)
return Coordinates(lineNo, 0);
local.x -= mCharAdvance.x;
int columnCoord = 0;
@@ -349,7 +352,7 @@ TextEditor::Coordinates TextEditor::ScreenPosToCoordinates(const ImVec2 &aPositi
}
}
return SanitizeCoordinates(Coordinates(lineNo, columnCoord - (columnCoord != 0)));
return SanitizeCoordinates(Coordinates(lineNo, columnCoord));
}
void TextEditor::DeleteWordLeft() {
@@ -891,14 +894,16 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
ImVec2 position = lineNumbersStartPos;
auto scrollX = ImGui::GetScrollX();
if (mSetScrollY)
SetScrollY();
auto scrollY = ImGui::GetScrollY();
if (mSetTopLine)
SetTopLine();
else
mTopLine = std::max<int>(0, std::floor((scrollY-mTopMargin) / mCharAdvance.y));
mTopLine = std::max<float>(0.0F, (scrollY-mTopMargin) / mCharAdvance.y);
auto lineNo = mTopLine;
int globalLineMax = mLines.size();
auto lineMax = std::clamp(lineNo + mNumberOfLinesDisplayed, 0, globalLineMax - 1);
float globalLineMax = mLines.size();
auto lineMax = std::clamp(lineNo + mNumberOfLinesDisplayed, 0.0F, globalLineMax-1.0F);
int totalDigitCount = std::floor(std::log10(globalLineMax)) + 1;
mLongest = GetLongestLineLength() * mCharAdvance.x;
@@ -906,7 +911,7 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
char buf[16];
if (mShowLineNumbers)
snprintf(buf, 16, " %d ", globalLineMax);
snprintf(buf, 16, " %d ", int(globalLineMax));
else
buf[0] = '\0';
mTextStart = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf, nullptr, nullptr).x + mLeftMargin;
@@ -915,7 +920,7 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
float spaceSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, " ", nullptr, nullptr).x;
while (lineNo <= lineMax) {
ImVec2 lineStartScreenPos = ImVec2(cursorScreenPos.x + mLeftMargin, cursorScreenPos.y + lineNo * mCharAdvance.y);
ImVec2 lineStartScreenPos = ImVec2(cursorScreenPos.x + mLeftMargin, mTopMargin + cursorScreenPos.y + std::floor(lineNo) * mCharAdvance.y);
ImVec2 textScreenPos = lineStartScreenPos;
auto &line = mLines[lineNo];
@@ -941,11 +946,8 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
ImVec2 vend(lineStartScreenPos.x + ssend, lineStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(vstart, vend, mPalette[(int)PaletteIndex::Selection]);
}
float startPos = 0;
if (scrollY < mTopMargin)
startPos = mTopMargin - scrollY;
ImVec2 lineNoStartScreenPos = ImVec2(position.x, startPos + position.y + (lineNo - mTopLine) * mCharAdvance.y);
auto start = ImVec2(lineNoStartScreenPos.x + mLineNumberFieldWidth, lineNoStartScreenPos.y);
ImVec2 lineNoStartScreenPos = ImVec2(position.x, mTopMargin + cursorScreenPos.y + std::floor(lineNo) * mCharAdvance.y);
auto start = ImVec2(lineNoStartScreenPos.x + mLineNumberFieldWidth, lineStartScreenPos.y);
bool focused = ImGui::IsWindowFocused();
if (!mIgnoreImGuiChild)
ImGui::EndChild();
@@ -960,14 +962,14 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
while (padding-- > 0) {
space += " ";
}
std::string lineNoStr = space + std::to_string(lineNo + 1);
TextUnformattedColoredAt(ImVec2(mLeftMargin + lineNoStartScreenPos.x, lineNoStartScreenPos.y), mPalette[(int) PaletteIndex::LineNumber], lineNoStr.c_str());
std::string lineNoStr = space + std::to_string((int)(lineNo + 1));
TextUnformattedColoredAt(ImVec2(mLeftMargin + lineNoStartScreenPos.x, lineStartScreenPos.y), mPalette[(int) PaletteIndex::LineNumber], lineNoStr.c_str());
}
// Draw breakpoints
if (mBreakpoints.count(lineNo + 1) != 0) {
auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineNoStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(ImVec2(lineNumbersStartPos.x, lineNoStartScreenPos.y), end, mPalette[(int)PaletteIndex::Breakpoint]);
auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(ImVec2(lineNumbersStartPos.x, lineStartScreenPos.y), end, mPalette[(int)PaletteIndex::Breakpoint]);
drawList->AddCircleFilled(start + ImVec2(0, mCharAdvance.y) / 2, mCharAdvance.y / 3, mPalette[(int)PaletteIndex::Breakpoint]);
drawList->AddCircle(start + ImVec2(0, mCharAdvance.y) / 2, mCharAdvance.y / 3, mPalette[(int)PaletteIndex::Default]);
@@ -977,9 +979,9 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
// Highlight the current line (where the cursor is)
if (!HasSelection()) {
auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineNoStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(ImVec2(lineNumbersStartPos.x, lineNoStartScreenPos.y), end, mPalette[(int)(focused ? PaletteIndex::CurrentLineFill : PaletteIndex::CurrentLineFillInactive)]);
drawList->AddRect(ImVec2(lineNumbersStartPos.x, lineNoStartScreenPos.y), end, mPalette[(int)PaletteIndex::CurrentLineEdge], 1.0f);
auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(ImVec2(lineNumbersStartPos.x, lineStartScreenPos.y), end, mPalette[(int)(focused ? PaletteIndex::CurrentLineFill : PaletteIndex::CurrentLineFillInactive)]);
drawList->AddRect(ImVec2(lineNumbersStartPos.x, lineStartScreenPos.y), end, mPalette[(int)PaletteIndex::CurrentLineEdge], 1.0f);
}
}
if (mShowLineNumbers && !mIgnoreImGuiChild)
@@ -1152,7 +1154,7 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
mLineBuffer.clear();
}
++lineNo;
lineNo = std::floor(lineNo + 1.0F);
}
}
if (!mIgnoreImGuiChild)
@@ -1167,9 +1169,9 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
ImGui::BeginChild(aTitle);
if (mShowLineNumbers)
ImGui::Dummy(ImVec2(mLongest, (globalLineMax - lineMax - 2) * mCharAdvance.y + ImGui::GetCurrentWindow()->InnerClipRect.GetHeight()));
ImGui::Dummy(ImVec2(mLongest, (globalLineMax - lineMax - 2.0F) * mCharAdvance.y + ImGui::GetCurrentWindow()->InnerClipRect.GetHeight()));
else
ImGui::Dummy(ImVec2(mLongest, (globalLineMax - 1 - lineMax + GetPageSize() - 1) * mCharAdvance.y));
ImGui::Dummy(ImVec2(mLongest, (globalLineMax - 1.0f - lineMax + GetPageSize() - 1.0f ) * mCharAdvance.y - 2 * ImGuiStyle().WindowPadding.y));
if (mScrollToCursor)
EnsureCursorVisible();
@@ -1177,8 +1179,6 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
if (mTopMarginChanged) {
mTopMarginChanged = false;
if (mTopMargin == 0)
mSavedScrollY = ImGui::GetScrollY();
auto window = ImGui::GetCurrentWindow();
auto maxScroll = window->ScrollMax.y;
if (maxScroll > 0) {
@@ -1194,10 +1194,8 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
if (mNewTopMargin > mTopMargin)
mShiftedScrollY = oldScrollY + pixelCount;
else if (mNewTopMargin > 0)
mShiftedScrollY = oldScrollY - pixelCount;
else
mShiftedScrollY = mSavedScrollY;
mShiftedScrollY = oldScrollY - pixelCount;
ImGui::SetScrollY(mShiftedScrollY);
mTopMargin = mNewTopMargin;
}
@@ -1222,6 +1220,7 @@ void TextEditor::Render(const char *aTitle, const ImVec2 &aSize, bool aBorder) {
if (mShowLineNumbers ) {
std::string lineNumber = " " + std::to_string(mLines.size()) + " ";
mLineNumberFieldWidth = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, lineNumber.c_str(), nullptr, nullptr).x + mLeftMargin;
ImGui::SetNextWindowPos(position);
ImGui::SetCursorScreenPos(position);
auto lineNoSize = ImVec2(mLineNumberFieldWidth, aSize.y);
if (!mIgnoreImGuiChild) {
@@ -1648,6 +1647,11 @@ void TextEditor::JumpToCoords(const Coordinates &aNewPos) {
void TextEditor::MoveUp(int aAmount, bool aSelect) {
ResetCursorBlinkTime();
auto oldPos = mState.mCursorPosition;
if (aAmount < 0) {
mScrollYIncrement = -1.0;
SetScrollY();
return;
}
mState.mCursorPosition.mLine = std::max(0, mState.mCursorPosition.mLine - aAmount);
if (oldPos != mState.mCursorPosition) {
if (aSelect) {
@@ -1671,10 +1675,16 @@ void TextEditor::MoveDown(int aAmount, bool aSelect) {
IM_ASSERT(mState.mCursorPosition.mColumn >= 0);
ResetCursorBlinkTime();
auto oldPos = mState.mCursorPosition;
if (aAmount < 0) {
mScrollYIncrement = 1.0;
SetScrollY();
return;
}
mState.mCursorPosition.mLine = std::clamp(mState.mCursorPosition.mLine + aAmount, 0, (int)mLines.size() - 1);
if (oldPos.mLine == (mLines.size() - 1)) {
mTopLine += aAmount;
mTopLine = std::clamp(mTopLine, 0, (int)mLines.size() - 1);
mTopLine = std::clamp(mTopLine, 0.0F, mLines.size() - 1.0F);
SetTopLine();
EnsureCursorVisible();
return;
@@ -2508,7 +2518,6 @@ bool TextEditor::FindReplaceHandler::Replace(TextEditor *editor, bool next) {
u.mAfter = editor->mState;
editor->AddUndo(u);
editor->mTextChanged = true;
mMatches.erase(mMatches.begin() + matchIndex - 1);
return true;
}
@@ -3002,6 +3011,17 @@ float TextEditor::TextDistanceToLineStart(const Coordinates &aFrom) const {
return distance;
}
void TextEditor::SetScrollY() {
if (!mWithinRender) {
mSetScrollY = true;
return;
} else {
mSetScrollY = false;
auto scrollY = ImGui::GetScrollY();
ImGui::SetScrollY(std::clamp(scrollY+mScrollYIncrement,0.0f,ImGui::GetScrollMaxY()));
}
}
void TextEditor::SetTopLine() {
if (!mWithinRender) {
mSetTopLine = true;
@@ -3065,9 +3085,9 @@ void TextEditor::EnsureCursorVisible() {
mOldTopMargin = mTopMargin;
}
int TextEditor::GetPageSize() const {
auto height = ImGui::GetCurrentWindow()->InnerClipRect.GetHeight() - mTopMargin - ImGui::GetStyle().FramePadding.y;
return (int)floor(height / mCharAdvance.y);
float TextEditor::GetPageSize() const {
auto height = ImGui::GetCurrentWindow()->InnerClipRect.GetHeight();
return height / mCharAdvance.y;
}
void TextEditor::ResetCursorBlinkTime() {

View File

@@ -1,20 +1,20 @@
cmake_minimum_required(VERSION 3.16)
# https://github.com/ocornut/imgui with custom modifications made to the OpenGL 3 and GLFW backends
project(imgui_custom)
# https://github.com/ocornut/imgui backends with custom modifications made to the OpenGL 3 and GLFW backends
project(imgui_backend)
set(CMAKE_CXX_STANDARD 17)
if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
add_library(imgui_custom OBJECT
add_library(imgui_backend OBJECT
source/imgui_impl_opengl3.cpp
source/imgui_impl_glfw.cpp
)
target_include_directories(imgui_custom PUBLIC
target_include_directories(imgui_backend PUBLIC
include
)
target_link_libraries(imgui_custom PRIVATE imgui_includes)
target_link_libraries(imgui_backend PRIVATE imgui_includes)
find_package(OpenGL REQUIRED)
find_package(Freetype REQUIRED)
@@ -35,9 +35,9 @@ if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
set(GLFW_LIBRARIES "glfw3")
endif ()
target_include_directories(imgui_custom PUBLIC ${FREETYPE_INCLUDE_DIRS} ${OpenGL_INCLUDE_DIRS})
target_link_directories(imgui_custom PUBLIC ${FREETYPE_LIBRARY_DIRS} ${OpenGL_LIBRARY_DIRS})
target_link_libraries(imgui_custom PUBLIC ${GLFW_LIBRARIES} ${OPENGL_LIBRARIES})
target_include_directories(imgui_backend PUBLIC ${FREETYPE_INCLUDE_DIRS} ${OpenGL_INCLUDE_DIRS})
target_link_directories(imgui_backend PUBLIC ${FREETYPE_LIBRARY_DIRS} ${OpenGL_LIBRARY_DIRS})
target_link_libraries(imgui_backend PUBLIC ${GLFW_LIBRARIES} ${OPENGL_LIBRARIES})
endif()
target_include_directories(imgui_all_includes INTERFACE include)

View File

@@ -6,7 +6,7 @@
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only).
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
@@ -28,15 +28,17 @@
struct GLFWwindow;
struct GLFWmonitor;
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
// Emscripten related initialization phase methods
// Emscripten related initialization phase methods (call after ImGui_ImplGlfw_InitForOpenGL)
#ifdef __EMSCRIPTEN__
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback(const char* canvas_selector);
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow* window, const char* canvas_selector);
//static inline void ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback(const char* canvas_selector) { ImGui_ImplGlfw_InstallEmscriptenCallbacks(nullptr, canvas_selector); } } // Renamed in 1.91.0
#endif
// GLFW callbacks install
@@ -59,4 +61,7 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key,
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);
// GLFW helpers
IMGUI_IMPL_API void ImGui_ImplGlfw_Sleep(int milliseconds);
#endif // #ifndef IMGUI_DISABLE

View File

@@ -6,7 +6,7 @@
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only).
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
@@ -21,9 +21,23 @@
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
// About Emscripten support:
// - Emscripten provides its own GLFW (3.2.1) implementation (syntax: "-sUSE_GLFW=3"), but Joystick is broken and several features are not supported (multiple windows, clipboard, timer, etc.)
// - A third-party Emscripten GLFW (3.4.0) implementation (syntax: "--use-port=contrib.glfw3") fixes the Joystick issue and implements all relevant features for the browser.
// See https://github.com/pongasoft/emscripten-glfw/blob/master/docs/Comparison.md for details.
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2024-11-05: [Docking] Added Linux workaround for spurious mouse up events emitted while dragging and creating new viewport. (#3158, #7733, #7922)
// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
// - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn
// 2024-07-31: Added ImGui_ImplGlfw_Sleep() helper function for usage by our examples app, since GLFW doesn't provide one.
// 2024-07-08: *BREAKING* Renamed ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback to ImGui_ImplGlfw_InstallEmscriptenCallbacks(), added GLFWWindow* parameter.
// 2024-07-08: Emscripten: Added support for GLFW3 contrib port (GLFW 3.4.0 features + bug fixes): to enable, replace -sUSE_GLFW=3 with --use-port=contrib.glfw3 (requires emscripten 3.1.59+) (https://github.com/pongasoft/emscripten-glfw)
// 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions.
// 2023-12-19: Emscripten: Added ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback() to register canvas selector and auto-resize GLFW window.
// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys.
// 2023-07-18: Inputs: Revert ignoring mouse data on GLFW_CURSOR_DISABLED as it can be used differently. User may set ImGuiConfigFLags_NoMouse if desired. (#5625, #6609)
@@ -104,15 +118,30 @@
//#include <GLFW/glfw3native.h> // for glfwGetCocoaWindow()
// #endif
// IMHEX PATCH END
#ifndef _WIN32
#include <unistd.h> // for usleep()
#endif
#ifdef __linux__
#include <string_view>
#include <cstdlib>
#endif
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
// IMHEX PATCH BEGIN
#include <emscripten_browser_clipboard.h>
static std::string clipboardContent;
// IMHEX PATCH END
#ifdef EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3
#include <GLFW/emscripten_glfw3.h>
#else
#define EMSCRIPTEN_USE_EMBEDDED_GLFW3
#endif
#endif
// We gather version tests as define in order to easily see which features are version-dependent.
@@ -159,12 +188,14 @@ struct ImGui_ImplGlfw_Data
double Time;
GLFWwindow* MouseWindow;
GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
bool MouseIgnoreButtonUpWaitForFocusLoss;
bool MouseIgnoreButtonUp;
ImVec2 LastValidMousePos;
GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST];
bool InstalledCallbacks;
bool CallbacksChainForAllWindows;
bool WantUpdateMonitors;
#ifdef __EMSCRIPTEN__
#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
const char* CanvasSelector;
#endif
@@ -198,8 +229,8 @@ static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData()
// Forward Declarations
static void ImGui_ImplGlfw_UpdateMonitors();
static void ImGui_ImplGlfw_InitPlatformInterface();
static void ImGui_ImplGlfw_ShutdownPlatformInterface();
static void ImGui_ImplGlfw_InitMultiViewportSupport();
static void ImGui_ImplGlfw_ShutdownMultiViewportSupport();
// Functions
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
@@ -224,9 +255,12 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
// IMHEX PATCH END
}
static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
// Not static to allow third-party code to use that if they want to (but undocumented)
ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode);
ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode)
{
switch (key)
IM_UNUSED(scancode);
switch (keycode)
{
case GLFW_KEY_TAB: return ImGuiKey_Tab;
case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow;
@@ -351,13 +385,34 @@ static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
// X11 does not include current pressed/released modifier key in 'mods' flags submitted by GLFW
// See https://github.com/ocornut/imgui/issues/6034 and https://github.com/glfw/glfw/issues/1630
static void ImGui_ImplGlfw_UpdateKeyModifiers(GLFWwindow* window)
static void ImGui_ImplGlfw_UpdateKeyModifiers(GLFWwindow* window, int mods)
{
// IMHEX PATCH BEGIN
ImGuiIO& io = ImGui::GetIO();
io.AddKeyEvent(ImGuiMod_Ctrl, (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS));
io.AddKeyEvent(ImGuiMod_Shift, (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS));
io.AddKeyEvent(ImGuiMod_Alt, (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS));
io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS));
#ifdef __linux__
static bool isX11 = [] {
const auto sessionType = std::getenv("XDG_SESSION_TYPE");
if (sessionType == nullptr)
return false;
return std::string_view(sessionType) == "x11";
}();
if (isX11) {
io.AddKeyEvent(ImGuiMod_Ctrl, (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS));
io.AddKeyEvent(ImGuiMod_Shift, (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS));
io.AddKeyEvent(ImGuiMod_Alt, (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS));
io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS));
} else
#endif
{
io.AddKeyEvent(ImGuiMod_Ctrl, (mods & GLFW_MOD_CONTROL) != 0);
io.AddKeyEvent(ImGuiMod_Shift, (mods & GLFW_MOD_SHIFT) != 0);
io.AddKeyEvent(ImGuiMod_Alt, (mods & GLFW_MOD_ALT) != 0);
io.AddKeyEvent(ImGuiMod_Super, (mods & GLFW_MOD_SUPER) != 0);
}
// IMHEX PATCH END
}
static bool ImGui_ImplGlfw_ShouldChainCallback(GLFWwindow* window)
@@ -372,7 +427,11 @@ void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int acti
if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
bd->PrevUserCallbackMousebutton(window, button, action, mods);
ImGui_ImplGlfw_UpdateKeyModifiers(window);
// Workaround for Linux: ignore mouse up events which are following an focus loss following a viewport creation
if (bd->MouseIgnoreButtonUp && action == GLFW_RELEASE)
return;
ImGui_ImplGlfw_UpdateKeyModifiers(window, mods);
ImGuiIO& io = ImGui::GetIO();
if (button >= 0 && button < ImGuiMouseButton_COUNT)
@@ -385,7 +444,7 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo
if (bd->PrevUserCallbackScroll != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
bd->PrevUserCallbackScroll(window, xoffset, yoffset);
#ifdef __EMSCRIPTEN__
#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
// Ignore GLFW events: will be processed in ImGui_ImplEmscripten_WheelCallback().
return;
#endif
@@ -394,9 +453,10 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo
io.AddMouseWheelEvent((float)xoffset, (float)yoffset);
}
// FIXME: should this be baked into ImGui_ImplGlfw_KeyToImGuiKey()? then what about the values passed to io.SetKeyEventNativeData()?
static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
{
#if GLFW_HAS_GETKEYNAME && !defined(__EMSCRIPTEN__)
#if GLFW_HAS_GETKEYNAME && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3)
// GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
// (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently)
// See https://github.com/glfw/glfw/issues/1502 for details.
@@ -407,7 +467,7 @@ static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr);
const char* key_name = glfwGetKeyName(key, scancode);
glfwSetErrorCallback(prev_error_callback);
#if GLFW_HAS_GETERROR && !defined(__EMSCRIPTEN__) // Eat errors (see #5908)
#if GLFW_HAS_GETERROR && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3) // Eat errors (see #5908)
(void)glfwGetError(nullptr);
#endif
if (key_name && key_name[0] != 0 && key_name[1] == 0)
@@ -436,7 +496,7 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, i
if (action != GLFW_PRESS && action != GLFW_RELEASE)
return;
ImGui_ImplGlfw_UpdateKeyModifiers(window);
ImGui_ImplGlfw_UpdateKeyModifiers(window, mods);
if (keycode >= 0 && keycode < IM_ARRAYSIZE(bd->KeyOwnerWindows))
bd->KeyOwnerWindows[keycode] = (action == GLFW_PRESS) ? window : nullptr;
@@ -444,7 +504,7 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, i
keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
ImGuiIO& io = ImGui::GetIO();
ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode);
ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode, scancode);
io.AddKeyEvent(imgui_key, (action == GLFW_PRESS));
io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code)
}
@@ -455,6 +515,10 @@ void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
bd->PrevUserCallbackWindowFocus(window, focused);
// Workaround for Linux: when losing focus with MouseIgnoreButtonUpWaitForFocusLoss set, we will temporarily ignore subsequent Mouse Up events
bd->MouseIgnoreButtonUp = (bd->MouseIgnoreButtonUpWaitForFocusLoss && focused == 0);
bd->MouseIgnoreButtonUpWaitForFocusLoss = false;
ImGuiIO& io = ImGui::GetIO();
io.AddFocusEvent(focused != 0);
}
@@ -515,7 +579,7 @@ void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
bd->WantUpdateMonitors = true;
}
#ifdef __EMSCRIPTEN__
#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEvent* ev, void*)
{
// Mimic Emscripten_HandleWheel() in SDL.
@@ -600,6 +664,7 @@ EM_JS(void, ImGui_ImplGlfw_EmscriptenOpenURL, (const char* url), { url = url ? U
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
//printf("GLFW_VERSION: %d.%d.%d (%d)", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION, GLFW_VERSION_COMBINED);
@@ -665,14 +730,9 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
if (install_callbacks)
ImGui_ImplGlfw_InstallCallbacks(window);
// Register Emscripten Wheel callback to workaround issue in Emscripten GLFW Emulation (#6096)
// We intentionally do not check 'if (install_callbacks)' here, as some users may set it to false and call GLFW callback themselves.
// FIXME: May break chaining in case user registered their own Emscripten callback?
#ifdef __EMSCRIPTEN__
emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, false, ImGui_ImplEmscripten_WheelCallback);
#endif
// Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
// Update monitor a first time during init
// (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
ImGui_ImplGlfw_UpdateMonitors();
glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
@@ -689,8 +749,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
#else
IM_UNUSED(main_viewport);
#endif
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
ImGui_ImplGlfw_InitPlatformInterface();
ImGui_ImplGlfw_InitMultiViewportSupport();
// Windows: register a WndProc hook so we can intercept some messages.
#ifdef _WIN32
@@ -699,6 +758,23 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc);
#endif
// Emscripten: the same application can run on various platforms, so we detect the Apple platform at runtime
// to override io.ConfigMacOSXBehaviors from its default (which is always false in Emscripten).
#ifdef __EMSCRIPTEN__
#if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817
if (emscripten::glfw3::IsRuntimePlatformApple())
{
ImGui::GetIO().ConfigMacOSXBehaviors = true;
// Due to how the browser (poorly) handles the Meta Key, this line essentially disables repeats when used.
// This means that Meta + V only registers a single key-press, even if the keys are held.
// This is a compromise for dealing with this issue in ImGui since ImGui implements key repeat itself.
// See https://github.com/pongasoft/emscripten-glfw/blob/v3.4.0.20240817/docs/Usage.md#the-problem-of-the-super-key
emscripten::glfw3::SetSuperPlusKeyTimeouts(10, 10);
}
#endif
#endif
bd->ClientApi = client_api;
return true;
}
@@ -724,12 +800,13 @@ void ImGui_ImplGlfw_Shutdown()
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplGlfw_ShutdownPlatformInterface();
ImGui_ImplGlfw_ShutdownMultiViewportSupport();
if (bd->InstalledCallbacks)
ImGui_ImplGlfw_RestoreCallbacks(bd->Window);
#ifdef __EMSCRIPTEN__
emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, false, nullptr);
#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
if (bd->CanvasSelector)
emscripten_set_wheel_callback(bd->CanvasSelector, nullptr, false, nullptr);
#endif
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
@@ -761,14 +838,14 @@ static void ImGui_ImplGlfw_UpdateMouseData()
ImGuiViewport* viewport = platform_io.Viewports[n];
GLFWwindow* window = (GLFWwindow*)viewport->PlatformHandle;
#ifdef __EMSCRIPTEN__
#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
const bool is_window_focused = true;
#else
const bool is_window_focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0;
#endif
if (is_window_focused)
{
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
// When multi-viewports are enabled, all Dear ImGui positions are same as OS positions.
if (io.WantSetMousePos)
glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y));
@@ -840,7 +917,6 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
{
// Show OS mouse cursor
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
// IMHEX PATCH BEGIN
#if !defined(_WIN32)
glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
@@ -861,7 +937,7 @@ static void ImGui_ImplGlfw_UpdateGamepads()
return;
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
#if GLFW_HAS_GAMEPAD_API && !defined(__EMSCRIPTEN__)
#if GLFW_HAS_GAMEPAD_API && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3)
GLFWgamepadstate gamepad;
if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad))
return;
@@ -940,13 +1016,9 @@ static void ImGui_ImplGlfw_UpdateMonitors()
// Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
float x_scale, y_scale;
glfwGetMonitorContentScale(glfw_monitors[n], &x_scale, &y_scale);
if (x_scale == 0.0f)
continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902.
monitor.DpiScale = x_scale;
// IMHEX PATCH BEGIN
// REASON: Prevent occasional crash when a monitor connection status is changed
if (x_scale > 0)
monitor.DpiScale = x_scale;
// IMHEX PATCH END
#endif
monitor.PlatformHandle = (void*)glfw_monitors[n]; // [...] GLFW doc states: "guaranteed to be valid only until the monitor configuration changes"
platform_io.Monitors.push_back(monitor);
@@ -978,6 +1050,7 @@ void ImGui_ImplGlfw_NewFrame()
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
bd->Time = current_time;
bd->MouseIgnoreButtonUp = false;
ImGui_ImplGlfw_UpdateMouseData();
ImGui_ImplGlfw_UpdateMouseCursor();
@@ -985,7 +1058,17 @@ void ImGui_ImplGlfw_NewFrame()
ImGui_ImplGlfw_UpdateGamepads();
}
#ifdef __EMSCRIPTEN__
// GLFW doesn't provide a portable sleep function
void ImGui_ImplGlfw_Sleep(int milliseconds)
{
#ifdef _WIN32
::Sleep(milliseconds);
#else
usleep(milliseconds * 1000);
#endif
}
#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
static EM_BOOL ImGui_ImplGlfw_OnCanvasSizeChange(int event_type, const EmscriptenUiEvent* event, void* user_data)
{
ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)user_data;
@@ -1006,7 +1089,7 @@ static EM_BOOL ImGui_ImplEmscripten_FullscreenChangeCallback(int event_type, con
// 'canvas_selector' is a CSS selector. The event listener is applied to the first element that matches the query.
// STRING MUST PERSIST FOR THE APPLICATION DURATION. PLEASE USE A STRING LITERAL OR ENSURE POINTER WILL STAY VALID.
void ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback(const char* canvas_selector)
void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow*, const char* canvas_selector)
{
IM_ASSERT(canvas_selector != nullptr);
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
@@ -1018,8 +1101,24 @@ void ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback(const char* canvas_sel
// Change the size of the GLFW window according to the size of the canvas
ImGui_ImplGlfw_OnCanvasSizeChange(EMSCRIPTEN_EVENT_RESIZE, {}, bd);
// Register Emscripten Wheel callback to workaround issue in Emscripten GLFW Emulation (#6096)
// We intentionally do not check 'if (install_callbacks)' here, as some users may set it to false and call GLFW callback themselves.
// FIXME: May break chaining in case user registered their own Emscripten callback?
emscripten_set_wheel_callback(bd->CanvasSelector, nullptr, false, ImGui_ImplEmscripten_WheelCallback);
}
#endif
#elif defined(EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3)
// When using --use-port=contrib.glfw3 for the GLFW implementation, you can override the behavior of this call
// by invoking emscripten_glfw_make_canvas_resizable afterward.
// See https://github.com/pongasoft/emscripten-glfw/blob/master/docs/Usage.md#how-to-make-the-canvas-resizable-by-the-user for an explanation
void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow* window, const char* canvas_selector)
{
GLFWwindow* w = (GLFWwindow*)(EM_ASM_INT({ return Module.glfwGetWindow(UTF8ToString($0)); }, canvas_selector));
IM_ASSERT(window == w); // Sanity check
IM_UNUSED(w);
emscripten_glfw_make_canvas_resizable(window, "window", nullptr);
}
#endif // #ifdef EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3
//--------------------------------------------------------------------------------------------------------
@@ -1091,6 +1190,11 @@ static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport)
ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)();
viewport->PlatformUserData = vd;
// Workaround for Linux: ignore mouse up events corresponding to losing focus of the previously focused window (#7733, #3158, #7922)
#ifdef __linux__
bd->MouseIgnoreButtonUpWaitForFocusLoss = true;
#endif
// GLFW 3.2 unfortunately always set focus on glfwCreateWindow() if GLFW_VISIBLE is set, regardless of GLFW_FOCUSED
// With GLFW 3.3, the hint GLFW_FOCUS_ON_SHOW fixes this problem
glfwWindowHint(GLFW_VISIBLE, false);
@@ -1152,6 +1256,7 @@ static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport)
if (bd->KeyOwnerWindows[i] == vd->Window)
ImGui_ImplGlfw_KeyCallback(vd->Window, i, 0, GLFW_RELEASE, 0); // Later params are only used for main viewport, on which this function is never called.
}
glfwDestroyWindow(vd->Window);
}
vd->Window = nullptr;
@@ -1324,7 +1429,7 @@ static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst
}
#endif // GLFW_HAS_VULKAN
static void ImGui_ImplGlfw_InitPlatformInterface()
static void ImGui_ImplGlfw_InitMultiViewportSupport()
{
// Register platform interface (will be coupled with a renderer interface)
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
@@ -1359,7 +1464,7 @@ static void ImGui_ImplGlfw_InitPlatformInterface()
main_viewport->PlatformHandle = (void*)bd->Window;
}
static void ImGui_ImplGlfw_ShutdownPlatformInterface()
static void ImGui_ImplGlfw_ShutdownMultiViewportSupport()
{
ImGui::DestroyPlatformWindows();
}

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.91.6
// dear imgui, v1.91.7
// (headers)
// Help:
@@ -28,8 +28,8 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.91.6"
#define IMGUI_VERSION_NUM 19160
#define IMGUI_VERSION "1.91.7"
#define IMGUI_VERSION_NUM 19170
#define IMGUI_HAS_TABLE
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch
#define IMGUI_HAS_DOCK // Docking WIP branch
@@ -141,6 +141,7 @@ Index of this file:
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif
@@ -700,6 +701,7 @@ namespace ImGui
// Widgets: List Boxes
// - This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label.
// - If you don't need a label you can probably simply use BeginChild() with the ImGuiChildFlags_FrameStyle flag for the same result.
// - You can submit contents and manage your selection state however you want it, by creating e.g. Selectable() or any other items.
// - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analoguous to how Combos are created.
// - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth
@@ -1136,8 +1138,8 @@ enum ImGuiWindowFlags_
// Obsolete names
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiWindowFlags_NavFlattened = 1 << 29, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call.
ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90.0: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call.
ImGuiWindowFlags_NavFlattened = 1 << 31, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call.
#endif
};
@@ -1219,7 +1221,7 @@ enum ImGuiInputTextFlags_
ImGuiInputTextFlags_CallbackAlways = 1 << 20, // Callback on each iteration. User code may query cursor position, modify text buffer.
ImGuiInputTextFlags_CallbackCharFilter = 1 << 21, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard.
ImGuiInputTextFlags_CallbackResize = 1 << 22, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this)
ImGuiInputTextFlags_CallbackEdit = 1 << 23, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)
ImGuiInputTextFlags_CallbackEdit = 1 << 23, // Callback on any edit. Note that InputText() already returns true on edit + you can always use IsItemEdited(). The callback is useful to manipulate the underlying buffer while focus is active.
// Obsolete names
//ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior
@@ -1242,14 +1244,16 @@ enum ImGuiTreeNodeFlags_
ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding() before the node.
ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line without using AllowOverlap mode.
ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (cover the indent area).
ImGuiTreeNodeFlags_SpanTextWidth = 1 << 13, // Narrow hit box + narrow hovering highlight, will only cover the label text.
ImGuiTreeNodeFlags_SpanAllColumns = 1 << 14, // Frame will span all columns of its container table (text will still fit in current column)
ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 15, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop)
ImGuiTreeNodeFlags_SpanLabelWidth = 1 << 13, // Narrow hit box + narrow hovering highlight, will only cover the label text.
ImGuiTreeNodeFlags_SpanAllColumns = 1 << 14, // Frame will span all columns of its container table (label will still fit in current column)
ImGuiTreeNodeFlags_LabelSpanAllColumns = 1 << 15, // Label will span all columns of its container table
//ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 16, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible
ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 17, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop)
ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog,
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7
ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth,// Renamed in 1.90.7
#endif
};
@@ -1457,6 +1461,7 @@ enum ImGuiDataType_
ImGuiDataType_Float, // float
ImGuiDataType_Double, // double
ImGuiDataType_Bool, // bool (provided for user convenience, not supported by scalar widgets)
ImGuiDataType_String, // char* (provided for user convenience, not supported by scalar widgets)
ImGuiDataType_COUNT
};
@@ -1865,6 +1870,7 @@ enum ImGuiSliderFlags_
ImGuiSliderFlags_WrapAround = 1 << 8, // Enable wrapping around from max to min and from min to max. Only supported by DragXXX() functions for now.
ImGuiSliderFlags_ClampOnInput = 1 << 9, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.
ImGuiSliderFlags_ClampZeroRange = 1 << 10, // Clamp even if min==max==0.0f. Otherwise due to legacy reason DragXXX functions don't clamp with those values. When your clamping limits are dynamic you almost always want to use it.
ImGuiSliderFlags_NoSpeedTweaks = 1 << 11, // Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic.
ImGuiSliderFlags_AlwaysClamp = ImGuiSliderFlags_ClampOnInput | ImGuiSliderFlags_ClampZeroRange,
ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed.
};
@@ -2535,7 +2541,7 @@ struct ImGuiIO
// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used.
// The callback function should return 0 by default.
// Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details)
// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)
// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit. Note that InputText() already returns true on edit + you can always use IsItemEdited(). The callback is useful to manipulate the underlying buffer while focus is active.
// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration
// - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB
// - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows
@@ -2810,6 +2816,7 @@ struct ImGuiListClipper
// - It is important that we are keeping those disabled by default so they don't leak in user space.
// - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h)
// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4.
// - We intentionally provide ImVec2*float but not float*ImVec2: this is rare enough and we want to reduce the surface for possible user mistake.
#ifdef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED
IM_MSVC_RUNTIME_CHECKS_OFF
@@ -3011,7 +3018,7 @@ struct ImGuiSelectionBasicStorage
IMGUI_API void Clear(); // Clear selection
IMGUI_API void Swap(ImGuiSelectionBasicStorage& r); // Swap two selections
IMGUI_API void SetItemSelected(ImGuiID id, bool selected); // Add/remove an item from selection (generally done by ApplyRequests() function)
IMGUI_API bool GetNextSelectedItem(void** opaque_it, ImGuiID* out_id); // Iterate selection with 'void* it = NULL; ImGuiId id; while (selection.GetNextSelectedItem(&it, &id)) { ... }'
IMGUI_API bool GetNextSelectedItem(void** opaque_it, ImGuiID* out_id); // Iterate selection with 'void* it = NULL; ImGuiID id; while (selection.GetNextSelectedItem(&it, &id)) { ... }'
inline ImGuiID GetStorageIdFromIndex(int idx) { return AdapterIndexToStorageId(this, idx); } // Convert index to item id based on provided adapter.
};
@@ -3399,7 +3406,7 @@ struct ImFontConfig
unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure.
float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future.
float RasterizerDensity; // 1.0f // DPI scale for rasterization, not altering other font metrics: make it easy to swap between e.g. a 100% and a 400% fonts for a zooming display. IMPORTANT: If you increase this it is expected that you increase font scale accordingly, otherwise quality may look lowered.
ImWchar EllipsisChar; // -1 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used.
ImWchar EllipsisChar; // 0 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used.
// [Internal]
char Name[40]; // Name (strictly to ease debugging)

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.91.6
// dear imgui, v1.91.7
// (internal structures/api)
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
@@ -101,6 +101,7 @@ Index of this file:
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated
#endif
@@ -139,6 +140,7 @@ struct ImGuiContext; // Main Dear ImGui context
struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine
struct ImGuiDataVarInfo; // Variable information (e.g. to access style variables from an enum)
struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum
struct ImGuiDeactivatedItemData; // Data for IsItemDeactivated()/IsItemDeactivatedAfterEdit() function.
struct ImGuiDockContext; // Docking system context
struct ImGuiDockRequest; // Docking system dock/undock queued request
struct ImGuiDockNode; // Docking system node (hold a list of Windows OR two child dock nodes)
@@ -472,7 +474,7 @@ static inline double ImRsqrt(double x) { return 1.0 / sqrt(x); }
template<typename T> static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; }
template<typename T> static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; }
template<typename T> static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }
template<typename T> static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); }
template<typename T> static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * (T)t); }
template<typename T> static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; }
template<typename T> static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; }
template<typename T> static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; }
@@ -842,8 +844,7 @@ struct ImGuiDataTypeInfo
// Extend ImGuiDataType_
enum ImGuiDataTypePrivate_
{
ImGuiDataType_String = ImGuiDataType_COUNT + 1,
ImGuiDataType_Pointer,
ImGuiDataType_Pointer = ImGuiDataType_COUNT + 1,
ImGuiDataType_ID,
};
@@ -929,7 +930,7 @@ enum ImGuiButtonFlagsPrivate_
ImGuiButtonFlags_PressedOnRelease = 1 << 7, // return true on release (default requires click+release)
ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, // return true on double-click (default requires click+release)
ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers)
//ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat
//ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat -> use ImGuiItemFlags_ButtonRepeat instead.
ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping
ImGuiButtonFlags_AllowOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable.
//ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press
@@ -1086,7 +1087,7 @@ struct IMGUI_API ImGuiGroupData
ImVec2 BackupCurrLineSize;
float BackupCurrLineTextBaseOffset;
ImGuiID BackupActiveIdIsAlive;
bool BackupActiveIdPreviousFrameIsAlive;
bool BackupDeactivatedIdIsAlive;
bool BackupHoveredIdIsAlive;
bool BackupIsSameLine;
bool EmitItem;
@@ -1137,8 +1138,10 @@ struct IMGUI_API ImGuiInputTextState
{
ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent).
ImStbTexteditState* Stb; // State for stb_textedit.h
ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set.
ImGuiID ID; // widget id owning the text state
int TextLen; // UTF-8 length of the string in TextA (in bytes)
const char* TextSrc; // == TextA.Data unless read-only, in which case == buf passed to InputText(). Field only set and valid _inside_ the call InputText() call.
ImVector<char> TextA; // main UTF8 buffer. TextA.Size is a buffer size! Should always be >= buf_size passed by user (and of course >= CurLenA + 1).
ImVector<char> TextToRevertTo; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered)
ImVector<char> CallbackTextBackup; // temporary storage for callback to support automatic reconcile of undo-stack
@@ -1148,9 +1151,8 @@ struct IMGUI_API ImGuiInputTextState
bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!)
bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
bool Edited; // edited this frame
ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set.
bool ReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version.
int ReloadSelectionStart; // POSITIONS ARE IN IMWCHAR units *NOT* UTF-8 this is why this is not exposed yet.
bool WantReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version.
int ReloadSelectionStart;
int ReloadSelectionEnd;
ImGuiInputTextState();
@@ -1270,11 +1272,11 @@ struct ImGuiNextItemData
struct ImGuiLastItemData
{
ImGuiID ID;
ImGuiItemFlags ItemFlags; // See ImGuiItemFlags_
ImGuiItemFlags ItemFlags; // See ImGuiItemFlags_ (called 'InFlags' before v1.91.4).
ImGuiItemStatusFlags StatusFlags; // See ImGuiItemStatusFlags_
ImRect Rect; // Full rectangle
ImRect NavRect; // Navigation scoring rectangle (not displayed)
// Rarely used fields are not explicitly cleared, only valid when the corresponding ImGuiItemStatusFlags ar set.
// Rarely used fields are not explicitly cleared, only valid when the corresponding ImGuiItemStatusFlags are set.
ImRect DisplayRect; // Display rectangle. ONLY VALID IF (StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) is set.
ImRect ClipRect; // Clip rectangle at the time of submitting item. ONLY VALID IF (StatusFlags & ImGuiItemStatusFlags_HasClipRect) is set..
ImGuiKeyChord Shortcut; // Shortcut at the time of submitting item. ONLY VALID IF (StatusFlags & ImGuiItemStatusFlags_HasShortcut) is set..
@@ -1337,6 +1339,15 @@ struct ImGuiPtrOrIndex
ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; }
};
// Data used by IsItemDeactivated()/IsItemDeactivatedAfterEdit() functions
struct ImGuiDeactivatedItemData
{
ImGuiID ID;
int ElapseFrame;
bool HasBeenEditedBefore;
bool IsAlive;
};
//-----------------------------------------------------------------------------
// [SECTION] Popup support
//-----------------------------------------------------------------------------
@@ -2244,9 +2255,9 @@ struct ImGuiContext
int FrameCountEnded;
int FrameCountPlatformEnded;
int FrameCountRendered;
ImGuiID WithinEndChildID; // Set within EndChild()
bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame()
bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed
bool WithinEndChild; // Set within EndChild()
bool GcCompactAll; // Request full GC
bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log()
void* TestEngine; // Test engine user data
@@ -2306,9 +2317,8 @@ struct ImGuiContext
ImGuiWindow* ActiveIdWindow;
ImGuiInputSource ActiveIdSource; // Activating source: ImGuiInputSource_Mouse OR ImGuiInputSource_Keyboard OR ImGuiInputSource_Gamepad
ImGuiID ActiveIdPreviousFrame;
bool ActiveIdPreviousFrameIsAlive;
bool ActiveIdPreviousFrameHasBeenEditedBefore;
ImGuiWindow* ActiveIdPreviousFrameWindow;
ImGuiDeactivatedItemData DeactivatedItemData;
ImGuiDataTypeStorage ActiveIdValueOnActivation; // Backup of initial value at the time of activation. ONLY SET BY SPECIFIC WIDGETS: DragXXX and SliderXXX.
ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation.
float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More