mirror of https://github.com/WerWolv/ImHex
Compare commits
34 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
77c1ee3e7a | |
|
|
4be2c33985 | |
|
|
3034d79373 | |
|
|
e7daa586ba | |
|
|
3f4bdfdf61 | |
|
|
ab5860dc9a | |
|
|
53b2347358 | |
|
|
a195179101 | |
|
|
fdccc55805 | |
|
|
55dce338b2 | |
|
|
03c217addb | |
|
|
a3a3f52b48 | |
|
|
477b284041 | |
|
|
b52495bc33 | |
|
|
46ed451712 | |
|
|
963afdce96 | |
|
|
3f18a9a536 | |
|
|
64b226e12d | |
|
|
b74dc3d8b9 | |
|
|
9668a885e8 | |
|
|
b7afbf4a74 | |
|
|
4784a82d51 | |
|
|
a1ff1af754 | |
|
|
5c6b20c0ec | |
|
|
79af360822 | |
|
|
fb23708220 | |
|
|
93f6ab25e6 | |
|
|
6faefed4f4 | |
|
|
6a159be861 | |
|
|
d7b43b54f9 | |
|
|
1a92425995 | |
|
|
347bdd9508 | |
|
|
b80e8b63c9 | |
|
|
621d529682 |
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
})
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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())) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 0c9fce2ffefecfdce794e1859584e25877b7b592
|
||||
Subproject commit 0e8aad961d66904cfda8d7cc894f6f6eee2d9f30
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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", "");
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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() },
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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") {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue