Compare commits

...

34 Commits

Author SHA1 Message Date
WerWolv 77c1ee3e7a build: Bumped version to 1.36.2 2024-12-28 16:09:51 +01:00
WerWolv 4be2c33985 fix: Crash when providing invalid version string to semantic version class
Fixes #2036
2024-12-28 15:59:48 +01:00
WerWolv 3034d79373 build: Bumped version to 1.36.1 2024-12-28 14:09:43 +01:00
WerWolv e7daa586ba build: Switch to custom lunasvg repo to allow offline builds 2024-12-28 13:45:21 +01:00
WerWolv 3f4bdfdf61 fix: Exception being thrown when getting version parts from invalid version 2024-12-28 13:45:07 +01:00
WerWolv ab5860dc9a impr: Display "ImHex" in title bar when null provider is open 2024-12-28 13:45:01 +01:00
WerWolv 53b2347358 impr: Allow command palette to be closed by clicking on the menu bar 2024-12-28 13:44:55 +01:00
WerWolv a195179101 fix: Rendering issues with text editor in bookmark view 2024-12-28 13:44:48 +01:00
WerWolv fdccc55805 fix: Ctrl sometimes getting stuck when pressing ALT GR and other keys at the same time
#2019
2024-12-28 13:44:42 +01:00
WerWolv 55dce338b2 impr: Better create hash popup size 2024-12-28 13:44:32 +01:00
WerWolv 03c217addb fix: Don't show library plugins in --plugins subcommand 2024-12-28 13:44:27 +01:00
WerWolv a3a3f52b48 impr: Make interactive tutorials select windows when they're highlighted 2024-12-28 13:44:19 +01:00
WerWolv 477b284041 fix: Tutorial highlights not working anymore correctly 2024-12-28 13:44:12 +01:00
WerWolv b52495bc33 build: Fix remaining build issues 2024-12-28 13:44:06 +01:00
WerWolv 46ed451712 fix: Warning on macOS about wrong format argument 2024-12-28 13:40:53 +01:00
WerWolv 963afdce96 fix: `ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback` -> `ImGui_ImplGlfw_InstallEmscriptenCallbacks` 2024-12-28 13:40:44 +01:00
WerWolv 3f18a9a536 fix: Wrong --reset-settings subcommand description 2024-12-28 13:40:36 +01:00
WerWolv 64b226e12d build: Updated more dependencies 2024-12-28 13:40:27 +01:00
WerWolv b74dc3d8b9 build: Updated dependencies 2024-12-28 13:40:11 +01:00
WerWolv 9668a885e8 fix: Added migration routine to fix shortcuts 2024-12-26 14:03:00 +01:00
WerWolv b7afbf4a74 feat: Added system to handle version migrations 2024-12-26 14:02:49 +01:00
paxcut 4784a82d51 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-26 14:02:43 +01:00
WerWolv a1ff1af754 fix: Disable ImGui assert that causes random crashes on resize 2024-12-26 14:02:34 +01:00
WerWolv 5c6b20c0ec build: Updated ImGui glfw backend 2024-12-26 14:02:25 +01:00
WerWolv 79af360822 fix: Crashes when disassembling data
Fixes #2025
2024-12-25 18:25:26 +01:00
WerWolv fb23708220 fix: Wrong localStorage key for achievements 2024-12-25 18:25:20 +01:00
WerWolv 93f6ab25e6 fix: Missing emscripten include 2024-12-25 18:25:16 +01:00
WerWolv 6faefed4f4 fix: Disable browser ctrl + S in web build 2024-12-25 18:25:10 +01:00
WerWolv 6a159be861 fix: Properly save achievements in web version 2024-12-25 18:25:00 +01:00
WerWolv d7b43b54f9 fix: Saving files in web version not working correctly 2024-12-25 18:24:53 +01:00
WerWolv 1a92425995 impr: Force update all installed content store items after an update 2024-12-25 18:24:44 +01:00
WerWolv 347bdd9508 fix: Unused variable in wasm build 2024-12-25 18:24:31 +01:00
WerWolv b80e8b63c9 fix: Certain shortcuts not being captured by ImHex Web 2024-12-25 18:24:23 +01:00
WerWolv 621d529682 fix: Shortcuts not working correctly in Web build 2024-12-25 18:23:54 +01:00
58 changed files with 3239 additions and 1296 deletions

2
.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"]

View File

@ -1 +1 @@
1.36.0
1.36.2

View File

@ -262,3 +262,10 @@ function js_resizeCanvas() {
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();
}
})

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

View File

@ -217,6 +217,7 @@ namespace hex {
EVENT_DEF(EventOSThemeChanged);
EVENT_DEF(EventDPIChanged, float, float);
EVENT_DEF(EventWindowFocused, bool);
EVENT_DEF(EventImHexUpdated, SemanticVersion, SemanticVersion);
/**
* @brief Called when the provider is created.

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>
@ -618,7 +619,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 +696,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);
}
/**

View File

@ -153,12 +153,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:
@ -255,6 +250,8 @@ namespace hex {
static void resumeShortcuts();
static void pauseShortcuts();
static void enableMacOSMode();
[[nodiscard]] static std::optional<Shortcut> getPreviousShortcut();
[[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts();

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

@ -6,6 +6,10 @@
#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,6 +267,12 @@ namespace hex {
if (json.empty())
return;
#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;
@ -264,6 +283,7 @@ namespace hex {
file.writeString(json.dump(4));
break;
}
#endif
}
}

View File

@ -630,7 +630,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) {

View File

@ -645,6 +645,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;
@ -794,16 +802,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 +840,7 @@ namespace hex {
}
bool isNightlyBuild() {
return getImHexVersion(false).ends_with("WIP");
return getImHexVersion().nightly();
}
bool updateImHex(UpdateType updateType) {

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

@ -12,6 +12,7 @@ namespace hex {
AutoReset<std::map<Shortcut, ShortcutManager::ShortcutEntry>> s_globalShortcuts;
std::atomic<bool> s_paused;
std::optional<Shortcut> s_prevShortcut;
bool s_macOSMode = false;
}
@ -78,22 +79,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 +98,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;
}
@ -267,13 +260,13 @@ 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)
@ -387,4 +380,9 @@ namespace hex {
return result;
}
void ShortcutManager::enableMacOSMode() {
s_macOSMode = true;
}
}

View File

@ -33,6 +33,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);
@ -87,6 +94,10 @@ namespace hex {
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;
}
if (id != 0 && boundingBox.Contains(ImGui::GetMousePos())) {

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

@ -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;
}
}

2
lib/third_party/fmt vendored

@ -1 +1 @@
Subproject commit 0c9fce2ffefecfdce794e1859584e25877b7b592
Subproject commit 0e8aad961d66904cfda8d7cc894f6f6eee2d9f30

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;
@ -631,7 +632,9 @@ private:
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();
@ -1222,6 +1224,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 +1651,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 +1679,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;
@ -3002,6 +3016,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 +3090,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

@ -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,25 @@
//#include <GLFW/glfw3native.h> // for glfwGetCocoaWindow()
// #endif
// IMHEX PATCH END
#ifndef _WIN32
#include <unistd.h> // for usleep()
#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 +183,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 +224,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 +250,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 +380,18 @@ 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(int mods)
{
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));
// IMHEX PATCH BEGIN
// The original version of this caused the CTRL key to sometimes get stuck when pressing ALT GR, SHIFT and Enter
// together in some ways
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 +406,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(mods);
ImGuiIO& io = ImGui::GetIO();
if (button >= 0 && button < ImGuiMouseButton_COUNT)
@ -385,7 +423,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 +432,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 +446,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 +475,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(mods);
if (keycode >= 0 && keycode < IM_ARRAYSIZE(bd->KeyOwnerWindows))
bd->KeyOwnerWindows[keycode] = (action == GLFW_PRESS) ? window : nullptr;
@ -444,7 +483,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 +494,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 +558,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 +643,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 +709,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 +728,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 +737,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 +779,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 +817,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 +896,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 +916,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 +995,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 +1029,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 +1037,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 +1068,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 +1080,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 +1169,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 +1235,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 +1408,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 +1443,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

@ -15592,7 +15592,7 @@ void ImGui::SetCurrentViewport(ImGuiWindow* current_window, ImGuiViewportP* view
return;
g.CurrentDpiScale = viewport ? viewport->DpiScale : 1.0f;
g.CurrentViewport = viewport;
IM_ASSERT(g.CurrentDpiScale > 0.0f && g.CurrentDpiScale < 99.0f); // Typical correct values would be between 1.0f and 4.0f
//IM_ASSERT(g.CurrentDpiScale > 0.0f && g.CurrentDpiScale < 99.0f); // Typical correct values would be between 1.0f and 4.0f
//IMGUI_DEBUG_LOG_VIEWPORT("[viewport] SetCurrentViewport changed '%s' 0x%08X\n", current_window ? current_window->Name : NULL, viewport ? viewport->ID : 0);
// Notify platform layer of viewport changes

View File

@ -10,6 +10,7 @@
#define LLVM_DEMANGLE_DEMANGLE_H
#include <cstddef>
#include <optional>
#include <string>
#include <string_view>
@ -32,7 +33,7 @@ enum : int {
/// Returns a non-NULL pointer to a NUL-terminated C style string
/// that should be explicitly freed, if successful. Otherwise, may return
/// nullptr if mangled_name is not a valid mangling or is nullptr.
char *itaniumDemangle(std::string_view mangled_name);
char *itaniumDemangle(std::string_view mangled_name, bool ParseParams = true);
enum MSDemangleFlags {
MSDF_None = 0,
@ -54,6 +55,9 @@ enum MSDemangleFlags {
char *microsoftDemangle(std::string_view mangled_name, size_t *n_read,
int *status, MSDemangleFlags Flags = MSDF_None);
std::optional<size_t>
getArm64ECInsertionPointInMangledName(std::string_view MangledName);
// Demangles a Rust v0 mangled symbol.
char *rustDemangle(std::string_view MangledName);
@ -67,7 +71,9 @@ char *dlangDemangle(std::string_view MangledName);
/// demangling occurred.
std::string demangle(std::string_view MangledName);
bool nonMicrosoftDemangle(std::string_view MangledName, std::string &Result);
bool nonMicrosoftDemangle(std::string_view MangledName, std::string &Result,
bool CanHaveLeadingDot = true,
bool ParseParams = true);
/// "Partial" demangler. This supports demangling a string into an AST
/// (typically an intermediate stage in itaniumDemangle) and querying certain
@ -102,7 +108,7 @@ struct ItaniumPartialDemangler {
char *getFunctionParameters(char *Buf, size_t *N) const;
char *getFunctionReturnType(char *Buf, size_t *N) const;
/// If this function has any any cv or reference qualifiers. These imply that
/// If this function has any cv or reference qualifiers. These imply that
/// the function is a non-static member function.
bool hasFunctionQualifiers() const;

View File

@ -86,6 +86,11 @@
#define DEMANGLE_FALLTHROUGH
#endif
#ifndef DEMANGLE_ASSERT
#include <cassert>
#define DEMANGLE_ASSERT(__expr, __msg) assert((__expr) && (__msg))
#endif
#define DEMANGLE_NAMESPACE_BEGIN namespace llvm { namespace itanium_demangle {
#define DEMANGLE_NAMESPACE_END } }

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@ NODE(QualType)
NODE(ConversionOperatorType)
NODE(PostfixQualifiedType)
NODE(ElaboratedTypeSpefType)
NODE(TransformedType)
NODE(NameType)
NODE(AbiTagAttr)
NODE(EnableIfAttr)
@ -36,6 +37,7 @@ NODE(SpecialName)
NODE(CtorVtableSpecialName)
NODE(QualifiedName)
NODE(NestedName)
NODE(MemberLikeFriendName)
NODE(LocalName)
NODE(ModuleName)
NODE(ModuleEntity)
@ -44,7 +46,9 @@ NODE(PixelVectorType)
NODE(BinaryFPType)
NODE(BitIntType)
NODE(SyntheticTemplateParamName)
NODE(TemplateParamQualifiedArg)
NODE(TypeTemplateParamDecl)
NODE(ConstrainedTypeTemplateParamDecl)
NODE(NonTypeTemplateParamDecl)
NODE(TemplateTemplateParamDecl)
NODE(TemplateParamPackDecl)
@ -91,5 +95,10 @@ NODE(DoubleLiteral)
NODE(LongDoubleLiteral)
NODE(BracedExpr)
NODE(BracedRangeExpr)
NODE(RequiresExpr)
NODE(ExprRequirement)
NODE(TypeRequirement)
NODE(NestedRequirement)
NODE(ExplicitObjectParameter)
#undef NODE

View File

@ -9,6 +9,7 @@
#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
#define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
#include "llvm/Demangle/Demangle.h"
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
#include <cassert>
@ -54,6 +55,10 @@ public:
}
}
// Delete the copy constructor and the copy assignment operator.
ArenaAllocator(const ArenaAllocator &) = delete;
ArenaAllocator &operator=(const ArenaAllocator &) = delete;
char *allocUnalignedBuffer(size_t Size) {
assert(Head && Head->Buf);
@ -137,6 +142,9 @@ enum class FunctionIdentifierCodeGroup { Basic, Under, DoubleUnder };
// It has a set of functions to parse mangled symbols into Type instances.
// It also has a set of functions to convert Type instances to strings.
class Demangler {
friend std::optional<size_t>
llvm::getArm64ECInsertionPointInMangledName(std::string_view MangledName);
public:
Demangler() = default;
virtual ~Demangler() = default;

View File

@ -34,7 +34,7 @@ differences, we want to keep the "core" generic demangling library
identical between both copies to simplify development and testing.
If you're working on the generic library, then do the work first in
libcxxabi, then run the cp-to-llvm.sh script in src/demangle. This
libcxxabi, then run libcxxabi/src/demangle/cp-to-llvm.sh. This
script takes as an optional argument the path to llvm, and copies the
changes you made to libcxxabi over. Note that this script just
blindly overwrites all changes to the generic library in llvm, so be

View File

@ -19,11 +19,9 @@
#include "DemangleConfig.h"
#include <array>
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>
#include <string_view>
@ -49,7 +47,7 @@ class OutputBuffer {
BufferCapacity = Need;
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr)
std::terminate();
std::abort();
}
}
@ -160,7 +158,7 @@ public:
}
void insert(size_t Pos, const char *S, size_t N) {
assert(Pos <= CurrentPosition);
DEMANGLE_ASSERT(Pos <= CurrentPosition, "");
if (N == 0)
return;
grow(N);
@ -173,7 +171,7 @@ public:
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const {
assert(CurrentPosition);
DEMANGLE_ASSERT(CurrentPosition, "");
return Buffer[CurrentPosition - 1];
}

View File

@ -24,7 +24,8 @@ std::string llvm::demangle(std::string_view MangledName) {
return Result;
if (starts_with(MangledName, '_') &&
nonMicrosoftDemangle(MangledName.substr(1), Result))
nonMicrosoftDemangle(MangledName.substr(1), Result,
/*CanHaveLeadingDot=*/false))
return Result;
if (char *Demangled = microsoftDemangle(MangledName, nullptr, nullptr)) {
@ -46,10 +47,18 @@ static bool isRustEncoding(std::string_view S) { return starts_with(S, "_R"); }
static bool isDLangEncoding(std::string_view S) { return starts_with(S, "_D"); }
bool llvm::nonMicrosoftDemangle(std::string_view MangledName,
std::string &Result) {
std::string &Result, bool CanHaveLeadingDot,
bool ParseParams) {
char *Demangled = nullptr;
// Do not consider the dot prefix as part of the demangled symbol name.
if (CanHaveLeadingDot && MangledName.size() > 0 && MangledName[0] == '.') {
MangledName.remove_prefix(1);
Result = ".";
}
if (isItaniumEncoding(MangledName))
Demangled = itaniumDemangle(MangledName);
Demangled = itaniumDemangle(MangledName, ParseParams);
else if (isRustEncoding(MangledName))
Demangled = rustDemangle(MangledName);
else if (isDLangEncoding(MangledName))
@ -58,7 +67,7 @@ bool llvm::nonMicrosoftDemangle(std::string_view MangledName,
if (!Demangled)
return false;
Result = Demangled;
Result += Demangled;
std::free(Demangled);
return true;
}

View File

@ -366,13 +366,13 @@ public:
using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
char *llvm::itaniumDemangle(std::string_view MangledName) {
char *llvm::itaniumDemangle(std::string_view MangledName, bool ParseParams) {
if (MangledName.empty())
return nullptr;
Demangler Parser(MangledName.data(),
MangledName.data() + MangledName.length());
Node *AST = Parser.parse();
Node *AST = Parser.parse(ParseParams);
if (!AST)
return nullptr;

View File

@ -24,6 +24,7 @@
#include <array>
#include <cctype>
#include <cstdio>
#include <optional>
#include <string_view>
#include <tuple>
@ -53,6 +54,18 @@ static bool consumeFront(std::string_view &S, std::string_view C) {
return true;
}
static bool consumeFront(std::string_view &S, std::string_view PrefixA,
std::string_view PrefixB, bool A) {
const std::string_view &Prefix = A ? PrefixA : PrefixB;
return consumeFront(S, Prefix);
}
static bool startsWith(std::string_view S, std::string_view PrefixA,
std::string_view PrefixB, bool A) {
const std::string_view &Prefix = A ? PrefixA : PrefixB;
return llvm::itanium_demangle::starts_with(S, Prefix);
}
static bool isMemberPointer(std::string_view MangledName, bool &Error) {
Error = false;
const char F = MangledName.front();
@ -2256,6 +2269,18 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) {
NodeList &TP = **Current;
// <auto-nttp> ::= $ M <type> <nttp>
const bool IsAutoNTTP = consumeFront(MangledName, "$M");
if (IsAutoNTTP) {
// The deduced type of the auto NTTP parameter isn't printed so
// we want to ignore the AST created from demangling the type.
//
// TODO: Avoid the extra allocations to the bump allocator in this case.
(void)demangleType(MangledName, QualifierMangleMode::Drop);
if (Error)
return nullptr;
}
TemplateParameterReferenceNode *TPRN = nullptr;
if (consumeFront(MangledName, "$$Y")) {
// Template alias
@ -2266,15 +2291,17 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) {
} else if (consumeFront(MangledName, "$$C")) {
// Type has qualifiers.
TP.N = demangleType(MangledName, QualifierMangleMode::Mangle);
} else if (llvm::itanium_demangle::starts_with(MangledName, "$1") ||
llvm::itanium_demangle::starts_with(MangledName, "$H") ||
llvm::itanium_demangle::starts_with(MangledName, "$I") ||
llvm::itanium_demangle::starts_with(MangledName, "$J")) {
} else if (startsWith(MangledName, "$1", "1", !IsAutoNTTP) ||
startsWith(MangledName, "$H", "H", !IsAutoNTTP) ||
startsWith(MangledName, "$I", "I", !IsAutoNTTP) ||
startsWith(MangledName, "$J", "J", !IsAutoNTTP)) {
// Pointer to member
TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
TPRN->IsMemberPointer = true;
MangledName.remove_prefix(1);
if (!IsAutoNTTP)
MangledName.remove_prefix(1); // Remove leading '$'
// 1 - single inheritance <name>
// H - multiple inheritance <name> <number>
// I - virtual inheritance <name> <number> <number>
@ -2317,12 +2344,13 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) {
TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
TPRN->Symbol = parse(MangledName);
TPRN->Affinity = PointerAffinity::Reference;
} else if (llvm::itanium_demangle::starts_with(MangledName, "$F") ||
llvm::itanium_demangle::starts_with(MangledName, "$G")) {
} else if (startsWith(MangledName, "$F", "F", !IsAutoNTTP) ||
startsWith(MangledName, "$G", "G", !IsAutoNTTP)) {
TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
// Data member pointer.
MangledName.remove_prefix(1);
if (!IsAutoNTTP)
MangledName.remove_prefix(1); // Remove leading '$'
char InheritanceSpecifier = MangledName.front();
MangledName.remove_prefix(1);
@ -2342,7 +2370,7 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) {
}
TPRN->IsMemberPointer = true;
} else if (consumeFront(MangledName, "$0")) {
} else if (consumeFront(MangledName, "$0", "0", !IsAutoNTTP)) {
// Integral non-type template parameter
bool IsNegative = false;
uint64_t Value = 0;
@ -2397,6 +2425,24 @@ void Demangler::dumpBackReferences() {
std::printf("\n");
}
std::optional<size_t>
llvm::getArm64ECInsertionPointInMangledName(std::string_view MangledName) {
std::string_view ProcessedName{MangledName};
// We only support this for MSVC-style C++ symbols.
if (!consumeFront(ProcessedName, '?'))
return std::nullopt;
// The insertion point is just after the name of the symbol, so parse that to
// remove it from the processed name.
Demangler D;
D.demangleFullyQualifiedSymbolName(ProcessedName);
if (D.Error)
return std::nullopt;
return MangledName.length() - ProcessedName.length();
}
char *llvm::microsoftDemangle(std::string_view MangledName, size_t *NMangled,
int *Status, MSDemangleFlags Flags) {
Demangler D;

@ -1 +1 @@
Subproject commit 23578c7461634623a5de903370310b3af5140536
Subproject commit 14df4816411ee9e391df0cfe5a62f67afe9687d9

File diff suppressed because it is too large Load Diff

View File

@ -331,9 +331,9 @@ namespace hex::init {
// Draw version information
// In debug builds, also display the current commit hash and branch
#if defined(DEBUG)
const static auto VersionInfo = hex::format("{0} : {1}@{2}", ImHexApi::System::getImHexVersion(), ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash());
const static auto VersionInfo = hex::format("{0} : {1}@{2}", ImHexApi::System::getImHexVersion().get(), ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash());
#else
const static auto VersionInfo = hex::format("{0}", ImHexApi::System::getImHexVersion());
const static auto VersionInfo = hex::format("{0}", ImHexApi::System::getImHexVersion().get());
#endif
drawList->AddText(ImVec2((this->m_splashBackgroundTexture.getSize().x - ImGui::CalcTextSize(VersionInfo.c_str()).x) / 2, 105), ImColor(0xFF, 0xFF, 0xFF, 0xFF), VersionInfo.c_str());
@ -497,7 +497,7 @@ namespace hex::init {
ImGui_ImplOpenGL3_Init("#version 150");
#elif defined(OS_WEB)
ImGui_ImplOpenGL3_Init();
ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback("#canvas");
ImGui_ImplGlfw_InstallEmscriptenCallbacks(m_window, "#canvas");
#else
ImGui_ImplOpenGL3_Init("#version 130");
#endif

View File

@ -40,7 +40,7 @@ int main(int argc, char **argv) {
}
// Log some system information to aid debugging when users share their logs
log::info("Welcome to ImHex {}!", ImHexApi::System::getImHexVersion());
log::info("Welcome to ImHex {}!", ImHexApi::System::getImHexVersion().get());
log::info("Compiled using commit {}@{}", ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash());
log::info("Running on {} {} ({})", ImHexApi::System::getOSName(), ImHexApi::System::getOSVersion(), ImHexApi::System::getArchitecture());
#if defined(OS_LINUX)

View File

@ -25,6 +25,10 @@ EM_JS(void, resizeCanvas, (), {
js_resizeCanvas();
});
EM_JS(bool, isMacOS, (), {
return navigator.userAgent.indexOf('Mac OS X') != -1
});
EM_JS(void, fixCanvasInPlace, (), {
document.getElementById('canvas').classList.add('canvas-fixed');
});
@ -126,6 +130,9 @@ namespace hex {
if (themeFollowSystem)
EventOSThemeChanged::post();
if (isMacOS())
ShortcutManager::enableMacOSMode();
}
void Window::beginNativeWindowFrame() {

View File

@ -256,10 +256,17 @@ namespace hex {
RegionTop * (cursor.y < (window.top + border.y)) |
RegionBottom * (cursor.y >= (window.bottom - border.y));
if (result != 0 && (ImGui::IsAnyItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId))) {
if (result != 0 && (ImGui::IsAnyItemHovered())) {
break;
}
if (ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)) {
if (result == RegionClient)
return HTCLIENT;
else
return HTCAPTION;
}
std::string_view hoveredWindowName = GImGui->HoveredWindow == nullptr ? "" : GImGui->HoveredWindow->Name;
if (!ImHexApi::System::impl::isWindowResizable()) {

View File

@ -81,6 +81,10 @@ namespace hex {
EventImHexStartupFinished::post();
TutorialManager::init();
#if defined(OS_MACOS)
ShortcutManager::enableMacOSMode();
#endif
}
Window::~Window() {
@ -525,17 +529,18 @@ namespace hex {
}
};
std::string localizedName = name.get();
if (currPopup->isModal())
createPopup(ImGui::BeginPopupModal(name, closeButton, flags));
createPopup(ImGui::BeginPopupModal(localizedName.c_str(), closeButton, flags));
else
createPopup(ImGui::BeginPopup(name, flags));
createPopup(ImGui::BeginPopup(localizedName.c_str(), flags));
if (!ImGui::IsPopupOpen(name) && displayFrameCount < 5) {
ImGui::OpenPopup(name);
if (!ImGui::IsPopupOpen(localizedName.c_str()) && displayFrameCount < 5) {
ImGui::OpenPopup(localizedName.c_str());
}
if (currPopup->shouldClose() || !open) {
log::debug("Closing popup '{}'", name);
log::debug("Closing popup '{}'", localizedName);
positionSet = sizeSet = false;
currPopup = nullptr;
@ -881,13 +886,12 @@ namespace hex {
EventWindowFocused::post(focused == GLFW_TRUE);
});
#if !defined(OS_WEB)
// Register key press callback
glfwSetInputMode(m_window, GLFW_LOCK_KEY_MODS, GLFW_TRUE);
glfwSetKeyCallback(m_window, [](GLFWwindow *window, int key, int scanCode, int action, int mods) {
std::ignore = mods;
#if !defined(OS_WEB)
// Handle A-Z keys using their ASCII value instead of the keycode
if (key >= GLFW_KEY_A && key <= GLFW_KEY_Z) {
std::string_view name = glfwGetKeyName(key, scanCode);
@ -902,6 +906,10 @@ namespace hex {
}
}
}
#else
std::ignore = scanCode;
// Emscripten doesn't support glfwGetKeyName. Just pass the value through.
#endif
if (key == GLFW_KEY_UNKNOWN) return;
@ -930,7 +938,6 @@ namespace hex {
}
}
});
#endif
// Register window close callback
glfwSetWindowCloseCallback(m_window, [](GLFWwindow *window) {
@ -1035,7 +1042,7 @@ namespace hex {
ImGui_ImplOpenGL3_Init("#version 150");
#elif defined(OS_WEB)
ImGui_ImplOpenGL3_Init();
ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback("#canvas");
ImGui_ImplGlfw_InstallEmscriptenCallbacks(m_window, "#canvas");
#else
ImGui_ImplOpenGL3_Init("#version 130");
#endif

View File

@ -41,7 +41,7 @@ namespace hex::plugin::builtin {
}
[[nodiscard]] u64 getActualSize() const override { return 0x00; }
[[nodiscard]] std::string getName() const override { return "None"; }
[[nodiscard]] std::string getName() const override { return "ImHex"; }
[[nodiscard]] std::vector<Description> getDataDescription() const override { return { }; }
void loadSettings(const nlohmann::json &settings) override { std::ignore = settings; }

View File

@ -71,6 +71,7 @@ namespace hex::plugin::builtin {
bool download(const paths::impl::DefaultPath *pathType, const std::string &fileName, const std::string &url);
bool remove(const paths::impl::DefaultPath *pathType, const std::string &fileName);
void updateAll();
private:
HttpRequest m_httpRequest = HttpRequest("GET", "");

View File

@ -1014,6 +1014,8 @@
"hex.builtin.view.pattern_editor.shortcut.move_word_right": "Move Cursor One Word to the Right",
"hex.builtin.view.pattern_editor.shortcut.move_up": "Move Cursor One Line Up",
"hex.builtin.view.pattern_editor.shortcut.move_down": "Move Cursor One Line Down",
"hex.builtin.view.pattern_editor.shortcut.move_pixel_up": "Move Cursor One Pixel Up",
"hex.builtin.view.pattern_editor.shortcut.move_pixel_down": "Move Cursor One Pixel Down",
"hex.builtin.view.pattern_editor.shortcut.move_page_up": "Move Cursor One Page Up",
"hex.builtin.view.pattern_editor.shortcut.move_page_down": "Move Cursor One Page Down",
"hex.builtin.view.pattern_editor.shortcut.move_home": "Move Cursor to the Start of the Line",

View File

@ -31,7 +31,7 @@ namespace hex::plugin::builtin {
std::ignore = args;
hex::log::print(std::string(romfs::get("logo.ans").string()),
ImHexApi::System::getImHexVersion(),
ImHexApi::System::getImHexVersion().get(),
ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash(),
__DATE__, __TIME__,
ImHexApi::System::isPortableVersion() ? "Portable" : "Installed");
@ -142,10 +142,10 @@ namespace hex::plugin::builtin {
hex::log::println("Loaded plugins:");
for (const auto &plugin : PluginManager::getPlugins()) {
if (plugin.isLibraryPlugin()) continue;
hex::log::print("- \033[1m{}\033[0m", plugin.getPluginName());
hex::log::println(" by {}", plugin.getPluginAuthor());
hex::log::println(" \033[2;3m{}\033[0m", plugin.getPluginDescription());
}

View File

@ -18,7 +18,7 @@ namespace hex::plugin::builtin {
nlohmann::json result;
result["build"] = {
{ "version", ImHexApi::System::getImHexVersion() },
{ "version", ImHexApi::System::getImHexVersion().get() },
{ "commit", ImHexApi::System::getCommitHash(true) },
{ "branch", ImHexApi::System::getCommitBranch() }
};

View File

@ -226,11 +226,15 @@ namespace hex::plugin::builtin {
});
EventWindowInitialized::subscribe([] {
if (ContentRegistry::Settings::read<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", "") == "") {
const auto currVersion = ImHexApi::System::getImHexVersion();
const auto prevLaunchVersion = ContentRegistry::Settings::read<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", "");
if (prevLaunchVersion == "") {
EventFirstLaunch::post();
}
ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", ImHexApi::System::getImHexVersion());
EventImHexUpdated::post(SemanticVersion(prevLaunchVersion), currVersion);
ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", currVersion.get(false));
});
EventWindowDeinitializing::subscribe([](GLFWwindow *window) {

View File

@ -39,9 +39,7 @@ namespace hex::plugin::builtin {
return false;
// Convert the current version string to a format that can be compared to the latest release
auto versionString = ImHexApi::System::getImHexVersion();
size_t versionLength = std::min(versionString.find_first_of('-'), versionString.length());
auto currVersion = "v" + versionString.substr(0, versionLength);
auto currVersion = "v" + ImHexApi::System::getImHexVersion().get(false);
// Get the latest release version string
auto latestVersion = releases["tag_name"].get<std::string_view>();
@ -59,7 +57,7 @@ namespace hex::plugin::builtin {
ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", uuid);
}
TaskManager::createBackgroundTask("hex.builtin.task.sending_statistics"_lang, [uuid, versionString](auto&) {
TaskManager::createBackgroundTask("hex.builtin.task.sending_statistics"_lang, [uuid](auto&) {
// To avoid potentially flooding our database with lots of dead users
// from people just visiting the website, don't send telemetry data from
// the web version
@ -71,7 +69,7 @@ namespace hex::plugin::builtin {
nlohmann::json telemetry = {
{ "uuid", uuid },
{ "format_version", "1" },
{ "imhex_version", versionString },
{ "imhex_version", ImHexApi::System::getImHexVersion().get(false) },
{ "imhex_commit", fmt::format("{}@{}", ImHexApi::System::getCommitHash(true), ImHexApi::System::getCommitBranch()) },
{ "install_type", ImHexApi::System::isPortableVersion() ? "Portable" : "Installed" },
{ "os", ImHexApi::System::getOSName() },

View File

@ -298,7 +298,7 @@ namespace hex::plugin::builtin {
ImGui::TextUnformatted("hex.builtin.oobe.server_contact.data_collected.version"_lang);
ImGui::TableNextColumn();
ImGuiExt::TextFormattedWrapped("{}\n{}@{}\n{}",
ImHexApi::System::getImHexVersion(),
ImHexApi::System::getImHexVersion().get(),
ImHexApi::System::getCommitHash(true),
ImHexApi::System::getCommitBranch(),
ImHexApi::System::isPortableVersion() ? "Portable" : "Installed"

View File

@ -158,7 +158,7 @@ namespace hex::plugin::builtin {
}
{
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, ImHexApi::System::getImHexVersion());
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, ImHexApi::System::getImHexVersion().get(false));
tar.writeString(MetadataPath, metadataContent);
}

View File

@ -285,9 +285,7 @@ namespace hex::plugin::builtin {
ImGui::BeginDisabled(m_drawShortcut.matches(m_defaultShortcut));
if (ImGuiExt::IconButton(ICON_VS_X, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
m_hasDuplicate = !ShortcutManager::updateShortcut(m_shortcut, m_defaultShortcut, m_view);
m_drawShortcut = m_defaultShortcut;
this->reset();
if (!m_hasDuplicate) {
m_shortcut = m_defaultShortcut;
settingChanged = true;
@ -356,6 +354,12 @@ namespace hex::plugin::builtin {
return keys;
}
void reset() {
m_hasDuplicate = !ShortcutManager::updateShortcut(m_shortcut, m_defaultShortcut, m_view);
m_drawShortcut = m_defaultShortcut;
}
private:
bool detectShortcut() {
if (const auto &shortcut = ShortcutManager::getPreviousShortcut(); shortcut.has_value()) {
@ -971,6 +975,21 @@ namespace hex::plugin::builtin {
ContentRegistry::Settings::add<ToolbarIconsWidget>("hex.builtin.setting.toolbar", "", "hex.builtin.setting.toolbar.icons");
}
ImHexApi::System::addMigrationRoutine("v1.36.1", [] {
log::warn("Resetting shortcut key settings for them to work with this version of ImHex");
for (const auto &category : ContentRegistry::Settings::impl::getSettings()) {
for (const auto &subcategory : category.subCategories) {
for (const auto &entry : subcategory.entries) {
if (auto keybindingWidget = dynamic_cast<KeybindingWidget*>(entry.widget.get())) {
keybindingWidget->reset();
}
}
}
}
ContentRegistry::Settings::impl::store();
});
}
static void loadLayoutSettings() {

View File

@ -193,7 +193,7 @@ namespace hex::plugin::builtin {
ImGui::TableNextColumn();
{
// Draw basic information about ImHex and its version
ImGuiExt::TextFormatted("ImHex Hex Editor v{} by WerWolv", ImHexApi::System::getImHexVersion());
ImGuiExt::TextFormatted("ImHex Hex Editor v{} by WerWolv", ImHexApi::System::getImHexVersion().get());
ImGui::Indent(25_scaled);
ImGuiExt::TextFormatted("Powered by Dear ImGui v{}", ImGui::GetVersion());
ImGui::Unindent(25_scaled);
@ -582,9 +582,9 @@ namespace hex::plugin::builtin {
static ReleaseNotes notes;
// Set up the request to get the release notes the first time the page is opened
const static auto ImHexVersionString = ImHexApi::System::getImHexVersion(false);
const static auto ImHexVersion = ImHexApi::System::getImHexVersion();
AT_FIRST_TIME {
static HttpRequest request("GET", GitHubApiURL + std::string("/releases/") + (ImHexVersionString.ends_with(".WIP") ? "latest" : ( "tags/v" + ImHexVersionString)));
static HttpRequest request("GET", GitHubApiURL + std::string("/releases/") + (ImHexVersion.nightly() ? "latest" : ( "tags/v" + ImHexVersion.get(false))));
m_releaseNoteRequest = request.execute();
};

View File

@ -30,7 +30,14 @@ namespace hex::plugin::builtin {
});
// Load settings
m_showPopup = ContentRegistry::Settings::read<bool>("hex.builtin.setting.interface", "hex.builtin.setting.interface.achievement_popup", true);
{
bool defaultValue = true;
#if defined(OS_WEB)
defaultValue = false;
#endif
m_showPopup = ContentRegistry::Settings::read<bool>("hex.builtin.setting.interface", "hex.builtin.setting.interface.achievement_popup", defaultValue);
}
}
ViewAchievements::~ViewAchievements() {

View File

@ -496,8 +496,10 @@ namespace hex::plugin::builtin {
editor.SetShowWhitespaces(false);
if (!locked || (locked && !comment.empty())) {
ImGuiExt::Header("hex.builtin.view.bookmarks.header.comment"_lang);
editor.Render("##comment", ImVec2(ImGui::GetContentRegionAvail().x, 150_scaled), true);
if (ImGuiExt::BeginSubWindow("hex.builtin.view.bookmarks.header.comment"_lang)) {
editor.Render("##comment", ImVec2(ImGui::GetContentRegionAvail().x, 150_scaled), false);
}
ImGuiExt::EndSubWindow();
if (editor.IsTextChanged())
comment = editor.GetText();

View File

@ -2513,6 +2513,11 @@ namespace hex::plugin::builtin {
editor->MoveUp(1, false);
});
ShortcutManager::addShortcut(this, ALT + Keys::Up + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.move_pixel_up", [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
editor->MoveUp(-1, false);
});
ShortcutManager::addShortcut(this, Keys::PageUp + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.move_page_up", [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
editor->MoveUp(editor->GetPageSize()-4, false);
@ -2523,6 +2528,11 @@ namespace hex::plugin::builtin {
editor->MoveDown(1, false);
});
ShortcutManager::addShortcut(this, ALT+ Keys::Down + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.move_pixel_down", [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
editor->MoveDown(-1, false);
});
ShortcutManager::addShortcut(this, Keys::PageDown + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.move_page_down", [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
editor->MoveDown(editor->GetPageSize()-4, false);

View File

@ -52,6 +52,16 @@ namespace hex::plugin::builtin {
ThemeManager::addTheme(themeFile.readString());
});
addCategory("hex.builtin.view.store.tab.yara", "yara", &paths::Yara);
TaskManager::doLater([this] {
// Force update all installed items after an update so that there's no old and incompatible versions around anymore
{
const auto prevUpdateVersion = ContentRegistry::Settings::read<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", "");
if (SemanticVersion(prevUpdateVersion) != ImHexApi::System::getImHexVersion()) {
updateAll();
}
}
});
}
@ -197,28 +207,7 @@ namespace hex::plugin::builtin {
ImGui::SameLine(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - 25_scaled);
ImGui::BeginDisabled(m_updateAllTask.isRunning() || m_updateCount == 0);
if (ImGuiExt::IconButton(ICON_VS_CLOUD_DOWNLOAD, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
m_updateAllTask = TaskManager::createTask("hex.builtin.task.updating_store"_lang, m_updateCount, [this](auto &task) {
for (auto &category : m_categories) {
for (auto &entry : category.entries) {
if (entry.hasUpdate) {
entry.downloading = this->download(category.path, entry.fileName, entry.link);
if (!m_download.valid())
continue;
m_download.wait();
while (m_download.valid() && m_download.wait_for(100ms) != std::future_status::ready) {
task.update();
}
entry.hasUpdate = false;
entry.downloading = false;
task.increment();
}
}
}
});
this->updateAll();
}
ImGuiExt::InfoTooltip(hex::format("hex.builtin.view.store.update_count"_lang, m_updateCount.load()).c_str());
@ -346,6 +335,36 @@ namespace hex::plugin::builtin {
return removed;
}
void ViewStore::updateAll() {
m_updateAllTask = TaskManager::createTask("hex.builtin.task.updating_store"_lang, m_updateCount, [this](auto &task) {
for (auto &category : m_categories) {
for (auto &entry : category.entries) {
if (entry.hasUpdate) {
entry.downloading = this->download(category.path, entry.fileName, entry.link);
if (!m_download.valid())
continue;
m_download.wait();
while (m_download.valid() && m_download.wait_for(100ms) != std::future_status::ready) {
task.update();
}
entry.hasUpdate = false;
entry.downloading = false;
task.increment();
}
}
}
TaskManager::doLater([] {
ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", ImHexApi::System::getImHexVersion().get(false));
});
});
}
void ViewStore::addCategory(const UnlocalizedString &unlocalizedName, const std::string &requestName, const paths::impl::DefaultPath *path, std::function<void()> downloadCallback) {
m_categories.push_back({ unlocalizedName, requestName, path, { }, std::move(downloadCallback) });
}

View File

@ -75,7 +75,7 @@ IMHEX_PLUGIN_SUBCOMMANDS() {
{ "pl", "", "Interact with the pattern language", hex::plugin::builtin::handlePatternLanguageCommand },
{ "hexdump", "", "Generate a hex dump of the provided file", hex::plugin::builtin::handleHexdumpCommand },
{ "demangle", "", "Demangle a mangled symbol", hex::plugin::builtin::handleDemangleCommand },
{ "reset-settings", "", "Demangle a mangled symbol", hex::plugin::builtin::handleSettingsResetCommand },
{ "reset-settings", "", "Resets all settings back to default", hex::plugin::builtin::handleSettingsResetCommand },
};
IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {

View File

@ -104,21 +104,23 @@ namespace hex::plugin::disasm {
std::vector<u8> data(std::min<u64>(32, evaluator->getSectionSize(sectionId) - address));
evaluator->readData(address, data.data(), data.size(), sectionId);
cs_insn instruction;
auto *instruction = cs_malloc(capstone);
ON_SCOPE_EXIT { cs_free(instruction, 1); };
const u8 *code = data.data();
size_t dataSize = data.size();
if (!cs_disasm_iter(capstone, &code, &dataSize, &instructionLoadAddress, &instruction)) {
if (!cs_disasm_iter(capstone, &code, &dataSize, &instructionLoadAddress, instruction)) {
err::E0012.throwError("Failed to disassemble instruction");
}
auto result = std::make_unique<PatternInstruction>(evaluator, address, instruction.size, 0);
auto result = std::make_unique<PatternInstruction>(evaluator, address, instruction->size, 0);
std::string instructionString;
if (instruction.mnemonic[0] != '\x00')
instructionString += instruction.mnemonic;
if (instruction.op_str[0] != '\x00') {
if (instruction->mnemonic[0] != '\x00')
instructionString += instruction->mnemonic;
if (instruction->op_str[0] != '\x00') {
instructionString += ' ';
instructionString += instruction.op_str;
instructionString += instruction->op_str;
}
result->setInstructionString(instructionString);

View File

@ -48,12 +48,14 @@ namespace hex::plugin::disasm {
m_disassemblerTask = TaskManager::createTask("hex.disassembler.view.disassembler.disassembling"_lang, m_regionToDisassemble.getSize(), [this](auto &task) {
csh capstoneHandle;
cs_insn instruction;
cs_mode mode = m_mode;
// Create a capstone disassembler instance
if (cs_open(Disassembler::toCapstoneArchitecture(m_architecture), mode, &capstoneHandle) == CS_ERR_OK) {
auto *instruction = cs_malloc(capstoneHandle);
ON_SCOPE_EXIT { cs_free(instruction, 1); };
// Tell capstone to skip data bytes
cs_option(capstoneHandle, CS_OPT_SKIPDATA, CS_OPT_ON);
@ -75,24 +77,24 @@ namespace hex::plugin::disasm {
// Ask capstone to disassemble the data
const u8 *code = buffer.data();
while (cs_disasm_iter(capstoneHandle, &code, &bufferSize, &instructionLoadAddress, &instruction)) {
while (cs_disasm_iter(capstoneHandle, &code, &bufferSize, &instructionLoadAddress, instruction)) {
task.update(instructionDataAddress);
// Convert the capstone instructions to our disassembly format
Disassembly disassembly = { };
disassembly.address = instruction.address;
disassembly.address = instruction->address;
disassembly.offset = instructionDataAddress - m_imageBaseAddress;
disassembly.size = instruction.size;
disassembly.mnemonic = instruction.mnemonic;
disassembly.operators = instruction.op_str;
disassembly.size = instruction->size;
disassembly.mnemonic = instruction->mnemonic;
disassembly.operators = instruction->op_str;
for (u16 j = 0; j < instruction.size; j++)
disassembly.bytes += hex::format("{0:02X} ", instruction.bytes[j]);
for (u16 j = 0; j < instruction->size; j++)
disassembly.bytes += hex::format("{0:02X} ", instruction->bytes[j]);
disassembly.bytes.pop_back();
m_disassembly.push_back(disassembly);
instructionDataAddress += instruction.size;
instructionDataAddress += instruction->size;
hadError = false;
}

View File

@ -156,6 +156,7 @@ namespace hex::plugin::hashes {
ImGui::OpenPopup("##CreateHash");
}
ImGui::SetNextWindowSize(scaled({ 400, 0 }), ImGuiCond_Always);
if (ImGui::BeginPopup("##CreateHash")) {
ImGuiExt::InputTextIcon("hex.hashes.view.hashes.hash_name"_lang, ICON_VS_SYMBOL_KEY, m_newHashName);
@ -175,7 +176,7 @@ namespace hex::plugin::hashes {
if (m_newHashName.empty() && m_selectedHash != nullptr)
m_newHashName = hex::format("{} {}", Lang(m_selectedHash->getUnlocalizedName()), static_cast<const char *>("hex.hashes.view.hashes.hash"_lang));
if (ImGuiExt::BeginSubWindow("hex.ui.common.settings"_lang, nullptr, scaled({ 400, 200 }))) {
if (ImGuiExt::BeginSubWindow("hex.ui.common.settings"_lang, nullptr, scaled({ 0, 250 }))) {
if (m_selectedHash != nullptr) {
auto startPos = ImGui::GetCursorPosY();
m_selectedHash->draw();