diff --git a/CMakeLists.txt b/CMakeLists.txt index b6ef1354e..d3614a655 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,11 @@ configurePackageCreation() add_executable(imhex ${application_type} source/main.cpp - source/window.cpp + + source/window/window.cpp + source/window/win_window.cpp + source/window/macos_window.cpp + source/window/linux_window.cpp source/init/splash_window.cpp source/init/tasks.cpp @@ -94,7 +98,7 @@ set_target_properties(imhex PROPERTIES CXX_VISIBILITY_PRESET hidden) target_link_directories(imhex PRIVATE ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS}) if (WIN32) - target_link_libraries(imhex magic ${CMAKE_DL_LIBS} capstone LLVMDemangle libimhex ${Python_LIBRARIES} wsock32 ws2_32 libyara) + target_link_libraries(imhex magic ${CMAKE_DL_LIBS} capstone LLVMDemangle libimhex ${Python_LIBRARIES} wsock32 ws2_32 libyara Dwmapi.lib) else () target_link_libraries(imhex magic ${CMAKE_DL_LIBS} capstone LLVMDemangle libimhex ${Python_LIBRARIES} dl pthread libyara) endif () diff --git a/README.md b/README.md index 6a40b1fda..24ac395ac 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

:mag: ImHex

-

A Hex Editor for Reverse Engineers, Programmers and people that value their eye sight when working at 3 AM.

+

A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.

'Build' workflow Status diff --git a/external/ImGui/include/imgui_imhex_extensions.h b/external/ImGui/include/imgui_imhex_extensions.h index 61443d1d2..d03f24eeb 100644 --- a/external/ImGui/include/imgui_imhex_extensions.h +++ b/external/ImGui/include/imgui_imhex_extensions.h @@ -6,6 +6,26 @@ namespace ImGui { + struct Texture { + ImTextureID textureId; + int width, height; + + [[nodiscard]] + constexpr bool valid() const noexcept { + return this->textureId != nullptr; + } + + [[nodiscard]] + constexpr operator ImTextureID() { + return this->textureId; + } + + [[nodiscard]] + auto size() const noexcept { + return ImVec2(this->width, this->height); + } + }; + bool IconHyperlink(const char *icon, const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); bool Hyperlink(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); bool BulletHyperlink(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); @@ -22,9 +42,9 @@ namespace ImGui { return static_cast(ImGui::GetTime() * 100) % 100 <= static_cast(ImGui::GetIO().DeltaTime * 100); } - std::tuple LoadImageFromPath(const char *path); - std::tuple LoadImageFromMemory(ImU8 *buffer, int size); - void UnloadImage(ImTextureID texture); + Texture LoadImageFromPath(const char *path); + Texture LoadImageFromMemory(ImU8 *buffer, int size); + void UnloadImage(Texture &texture); enum ImGuiCustomCol { ImGuiCustomCol_DescButton, diff --git a/external/ImGui/include/imgui_impl_glfw.h b/external/ImGui/include/imgui_impl_glfw.h index 6abb40564..079255fcf 100644 --- a/external/ImGui/include/imgui_impl_glfw.h +++ b/external/ImGui/include/imgui_impl_glfw.h @@ -32,4 +32,4 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); -IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); +IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); \ No newline at end of file diff --git a/external/ImGui/source/imgui_imhex_extensions.cpp b/external/ImGui/source/imgui_imhex_extensions.cpp index 43c69a091..b260feadc 100644 --- a/external/ImGui/source/imgui_imhex_extensions.cpp +++ b/external/ImGui/source/imgui_imhex_extensions.cpp @@ -235,7 +235,7 @@ namespace ImGui { colors[ImGuiCustomCol_DescButtonActive] = ImColor(80, 80, 120); } - std::tuple LoadImageFromPath(const char *path) { + Texture LoadImageFromPath(const char *path) { int imageWidth = 0; int imageHeight = 0; @@ -261,7 +261,7 @@ namespace ImGui { return { reinterpret_cast(static_cast(texture)), imageWidth, imageHeight }; } - std::tuple LoadImageFromMemory(ImU8 *buffer, int size) { + Texture LoadImageFromMemory(ImU8 *buffer, int size) { int imageWidth = 0; int imageHeight = 0; @@ -288,12 +288,14 @@ namespace ImGui { return { reinterpret_cast(static_cast(texture)), imageWidth, imageHeight }; } - void UnloadImage(ImTextureID texture) { - if (texture == nullptr) + void UnloadImage(Texture &texture) { + if (texture.textureId == nullptr) return; - auto glTextureId = static_cast(reinterpret_cast(texture)); + auto glTextureId = static_cast(reinterpret_cast(texture.textureId)); glDeleteTextures(1, &glTextureId); + + texture = { nullptr, 0, 0 }; } } \ No newline at end of file diff --git a/external/curl b/external/curl index 31480dbd3..bfbde883a 160000 --- a/external/curl +++ b/external/curl @@ -1 +1 @@ -Subproject commit 31480dbd37fa7ea90bb9fa791b2716fc43ef6934 +Subproject commit bfbde883af33397943df68a3ae01847a634d33bf diff --git a/include/window.hpp b/include/window.hpp index 948735e48..ecb5f643e 100644 --- a/include/window.hpp +++ b/include/window.hpp @@ -8,9 +8,12 @@ #include #include +#include + struct GLFWwindow; struct ImGuiSettingsHandler; + namespace hex { class Window { @@ -28,6 +31,10 @@ namespace hex { bool setFont(const std::filesystem::path &font_path); private: + void setupNativeWindow(); + void updateNativeWindow(); + void drawTitleBar(); + void frameBegin(); void frame(); void frameEnd(); @@ -47,14 +54,18 @@ namespace hex { bool m_demoWindowOpen = false; bool m_layoutConfigured = false; + std::string m_windowTitle; + double m_lastFrameTime; bool m_prevKeysDown[512]; std::string m_availableUpdate; - u32 m_bannerWidth = 0, m_bannerHeight = 0; - void *m_bannerTexture = nullptr; + ImGui::Texture m_bannerTexture; + ImGui::Texture m_logoTexture; + + std::filesystem::path m_safetyBackupPath; }; diff --git a/plugins/libimhex/include/hex/resources.hpp b/plugins/libimhex/include/hex/resources.hpp index 0d556caeb..bccb657cd 100644 --- a/plugins/libimhex/include/hex/resources.hpp +++ b/plugins/libimhex/include/hex/resources.hpp @@ -9,6 +9,8 @@ RESOURCE_EXPORT(splash); RESOURCE_EXPORT(banner_light); RESOURCE_EXPORT(banner_dark); +RESOURCE_EXPORT(imhex_logo); + RESOURCE_EXPORT(cacert); diff --git a/plugins/libimhex/source/resources.cpp b/plugins/libimhex/source/resources.cpp index 1cf152223..d8dfe7ff6 100644 --- a/plugins/libimhex/source/resources.cpp +++ b/plugins/libimhex/source/resources.cpp @@ -46,5 +46,6 @@ RESOURCE(banner_light, "../../../res/resources/banner_light.png"); RESOURCE(banner_dark, "../../../res/resources/banner_dark.png"); RESOURCE(splash, "../../../res/resources/splash.png"); +RESOURCE(imhex_logo, "../../../res/resources/logo.png"); RESOURCE(cacert, "../../../res/resources/cacert.pem"); \ No newline at end of file diff --git a/res/resources/logo.png b/res/resources/logo.png new file mode 100644 index 000000000..796d7cfa9 Binary files /dev/null and b/res/resources/logo.png differ diff --git a/source/init/splash_window.cpp b/source/init/splash_window.cpp index 8044a1fbe..a6ce1e492 100644 --- a/source/init/splash_window.cpp +++ b/source/init/splash_window.cpp @@ -67,10 +67,9 @@ namespace hex::init { } bool WindowSplash::loop() { - ImTextureID splashTexture; - u32 splashWidth, splashHeight; + ImGui::Texture splashTexture; - std::tie(splashTexture, splashWidth, splashHeight) = ImGui::LoadImageFromMemory(splash, splash_size); + splashTexture = ImGui::LoadImageFromMemory(splash, splash_size); if (splashTexture == nullptr) { log::fatal("Could not load splash screen image!"); @@ -93,7 +92,7 @@ namespace hex::init { auto drawList = ImGui::GetOverlayDrawList(); - drawList->AddImage(splashTexture, ImVec2(0, 0), ImVec2(splashWidth, splashHeight) * this->m_globalScale); + drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.size() * this->m_globalScale); drawList->AddText(ImVec2(15, 120) * this->m_globalScale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("WerWolv 2020 - {0}", &__DATE__[7]).c_str()); @@ -103,8 +102,8 @@ namespace hex::init { drawList->AddText(ImVec2(15, 140) * this->m_globalScale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0}", IMHEX_VERSION).c_str()); #endif - drawList->AddRectFilled(ImVec2(0, splashHeight - 5) * this->m_globalScale, ImVec2(splashWidth * this->m_progress, splashHeight) * this->m_globalScale, 0xFFFFFFFF); - drawList->AddText(ImVec2(15, splashHeight - 25) * this->m_globalScale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), + drawList->AddRectFilled(ImVec2(0, splashTexture.size().y - 5) * this->m_globalScale, ImVec2(splashTexture.size().x * this->m_progress, splashTexture.size().y) * this->m_globalScale, 0xFFFFFFFF); + drawList->AddText(ImVec2(15, splashTexture.size().y - 25) * this->m_globalScale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str()); } diff --git a/source/window/linux_window.cpp b/source/window/linux_window.cpp new file mode 100644 index 000000000..fc0acf5e5 --- /dev/null +++ b/source/window/linux_window.cpp @@ -0,0 +1,17 @@ +#include "window.hpp" + +#if defined(OS_LINUX) + + namespace hex { + + void Window::setupNativeWindow() { + + } + + void Window::updateNativeWindow() { + + } + + } + +#endif \ No newline at end of file diff --git a/source/window/macos_window.cpp b/source/window/macos_window.cpp new file mode 100644 index 000000000..8ff09a68d --- /dev/null +++ b/source/window/macos_window.cpp @@ -0,0 +1,17 @@ +#include "window.hpp" + +#if defined(OS_MACOS) + + namespace hex { + + void Window::setupNativeWindow() { + + } + + void Window::updateNativeWindow() { + + } + + } + +#endif \ No newline at end of file diff --git a/source/window/win_window.cpp b/source/window/win_window.cpp new file mode 100644 index 000000000..9a28c64ea --- /dev/null +++ b/source/window/win_window.cpp @@ -0,0 +1,184 @@ +#include "window.hpp" + +#if defined(OS_WINDOWS) + + #include + + #include + #define GLFW_EXPOSE_NATIVE_WIN32 + #include + #include + #include + #include + #include + + #include + + namespace hex { + static LONG_PTR oldWndProc; + static float titleBarHeight; + static ImGuiMouseCursor mouseCursorIcon; + + LRESULT wndProcImHex(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch (uMsg) { + case WM_NCCALCSIZE: { + auto& params = *reinterpret_cast(lParam); + RECT &rect = params.rgrc[0]; + + WINDOWPLACEMENT placement; + if (!::GetWindowPlacement(hwnd, &placement) || placement.showCmd != SW_MAXIMIZE) + return 0; + + auto monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL); + if (monitor == nullptr) { + return 0; + } + + MONITORINFO monitor_info{}; + monitor_info.cbSize = sizeof(monitor_info); + if (!::GetMonitorInfoW(monitor, &monitor_info)) + return 0; + + rect = monitor_info.rcWork; + + return 0; + } + case WM_SETCURSOR: { + auto cursorPos = LOWORD(lParam); + + switch (cursorPos) { + case HTRIGHT: + case HTLEFT: + mouseCursorIcon = ImGuiMouseCursor_ResizeEW; + return TRUE; + case HTTOP: + case HTBOTTOM: + mouseCursorIcon = ImGuiMouseCursor_ResizeNS; + return TRUE; + case HTTOPLEFT: + case HTBOTTOMRIGHT: + mouseCursorIcon = ImGuiMouseCursor_ResizeNWSE; + return TRUE; + case HTTOPRIGHT: + case HTBOTTOMLEFT: + mouseCursorIcon = ImGuiMouseCursor_ResizeNESW; + return TRUE; + default: + mouseCursorIcon = ImGuiMouseCursor_None; + return TRUE; + } + } + case WM_NCHITTEST: { + POINT cursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + + const POINT border{ + ::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER), + ::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER) + }; + RECT window; + if (!::GetWindowRect(hwnd, &window)) { + return HTNOWHERE; + } + + constexpr auto RegionClient = 0b0000; + constexpr auto RegionLeft = 0b0001; + constexpr auto RegionRight = 0b0010; + constexpr auto RegionTop = 0b0100; + constexpr auto RegionBottom = 0b1000; + + const auto result = + RegionLeft * (cursor.x < (window.left + border.x)) | + RegionRight * (cursor.x >= (window.right - border.x)) | + RegionTop * (cursor.y < (window.top + border.y)) | + RegionBottom * (cursor.y >= (window.bottom - border.y)); + + switch (result) { + case RegionLeft: + return HTLEFT; + case RegionRight: + return HTRIGHT; + case RegionTop: + return HTTOP; + case RegionBottom: + return HTBOTTOM; + case RegionTop | RegionLeft: + return HTTOPLEFT; + case RegionTop | RegionRight: + return HTTOPRIGHT; + case RegionBottom | RegionLeft: + return HTBOTTOMLEFT; + case RegionBottom | RegionRight: + return HTBOTTOMRIGHT; + case RegionClient: + if ((cursor.y < (window.top + titleBarHeight)) && !ImGui::IsAnyItemHovered()) + return HTCAPTION; + else break; + } + } + } + + return CallWindowProc((WNDPROC)oldWndProc, hwnd, uMsg, wParam, lParam); + } + + void Window::setupNativeWindow() { + auto hwnd = glfwGetWin32Window(this->m_window); + oldWndProc = SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)wndProcImHex); + MARGINS borderless = {1,1,1,1}; + DwmExtendFrameIntoClientArea(hwnd, &borderless); + SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_ASYNCWINDOWPOS | SWP_NOSIZE | SWP_NOMOVE); + SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_POPUP | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | WS_SYSMENU); + } + + void Window::updateNativeWindow() { + titleBarHeight = ImGui::GetCurrentWindow()->MenuBarHeight(); + + if (mouseCursorIcon != ImGuiMouseCursor_None) + ImGui::SetMouseCursor(mouseCursorIcon); + } + + void Window::drawTitleBar() { + auto buttonSize = ImVec2(titleBarHeight * 1.5F, titleBarHeight); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_MenuBarBg)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabActive)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabHovered)); + + ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * 6); + #if defined(DEBUG) + if (ImGui::Button(ICON_VS_DEBUG, buttonSize)) + hex::openWebpage("https://imhex.werwolv.net/debug"); + #endif + if (ImGui::Button(ICON_VS_SMILEY, buttonSize)) + hex::openWebpage("mailto://hey@werwolv.net"); + + ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * 3); + if (ImGui::Button(ICON_VS_CHROME_MINIMIZE, buttonSize)) + glfwIconifyWindow(this->m_window); + if (glfwGetWindowAttrib(this->m_window, GLFW_MAXIMIZED)) { + if (ImGui::Button(ICON_VS_CHROME_RESTORE, buttonSize)) + glfwRestoreWindow(this->m_window); + } else { + if (ImGui::Button(ICON_VS_CHROME_MAXIMIZE, buttonSize)) + glfwMaximizeWindow(this->m_window); + } + + ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xFF7A70F1); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF2311E8); + + + if (ImGui::Button(ICON_VS_CHROME_CLOSE, buttonSize)) { + EventManager::post(); + EventManager::post(this->m_window); + } + + ImGui::PopStyleColor(5); + ImGui::PopStyleVar(); + + ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ImGui::CalcTextSize(this->m_windowTitle.c_str()).x) / 2); + ImGui::TextUnformatted(this->m_windowTitle.c_str()); + } + + } + +#endif \ No newline at end of file diff --git a/source/window.cpp b/source/window/window.cpp similarity index 89% rename from source/window.cpp rename to source/window/window.cpp index 58a14a6ad..3748d657f 100644 --- a/source/window.cpp +++ b/source/window/window.cpp @@ -80,33 +80,35 @@ namespace hex { { auto theme = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color"); - if (this->m_bannerTexture != nullptr) + if (this->m_bannerTexture.valid()) ImGui::UnloadImage(this->m_bannerTexture); if (theme.is_number()) { switch (static_cast(theme)) { default: - case 0: /* Dark theme */ - ImGui::StyleColorsDark(); - ImGui::StyleCustomColorsDark(); - ImPlot::StyleColorsDark(); - std::tie(this->m_bannerTexture, this->m_bannerWidth, this->m_bannerHeight) = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size); - break; - case 1: /* Light theme */ - ImGui::StyleColorsLight(); - ImGui::StyleCustomColorsLight(); - ImPlot::StyleColorsLight(); - std::tie(this->m_bannerTexture, this->m_bannerWidth, this->m_bannerHeight) = ImGui::LoadImageFromMemory(banner_light, banner_light_size); break; - case 2: /* Classic theme */ - ImGui::StyleColorsClassic(); - ImGui::StyleCustomColorsClassic(); - ImPlot::StyleColorsClassic(); - std::tie(this->m_bannerTexture, this->m_bannerWidth, this->m_bannerHeight) = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size); break; + case 0: /* Dark theme */ + ImGui::StyleColorsDark(); + ImGui::StyleCustomColorsDark(); + ImPlot::StyleColorsDark(); + this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size); + break; + case 1: /* Light theme */ + ImGui::StyleColorsLight(); + ImGui::StyleCustomColorsLight(); + ImPlot::StyleColorsLight(); + this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_light, banner_light_size); + break; + case 2: /* Classic theme */ + ImGui::StyleColorsClassic(); + ImGui::StyleCustomColorsClassic(); + ImPlot::StyleColorsClassic(); + this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size); + break; } ImGui::GetStyle().Colors[ImGuiCol_DockingEmptyBg] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg]; - if (this->m_bannerTexture == nullptr) { + if (!this->m_bannerTexture.valid()) { log::fatal("Failed to load banner texture!"); exit(EXIT_FAILURE); } @@ -181,6 +183,7 @@ namespace hex { if (ProjectFile::hasUnsavedChanges()) title += " (*)"; + this->m_windowTitle = title; glfwSetWindowTitle(this->m_window, title.c_str()); }); @@ -217,6 +220,8 @@ namespace hex { std::signal(SIGILL, signalHandler); std::signal(SIGABRT, signalHandler); std::signal(SIGFPE, signalHandler); + + this->m_logoTexture = ImGui::LoadImageFromMemory(imhex_logo, imhex_logo_size); } Window::~Window() { @@ -229,6 +234,7 @@ namespace hex { EventManager::unsubscribe(this); ImGui::UnloadImage(this->m_bannerTexture); + ImGui::UnloadImage(this->m_logoTexture); } void Window::loop() { @@ -320,10 +326,10 @@ namespace hex { ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking - | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse - | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize - | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoBringToFrontOnFocus - | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; + | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse + | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize + | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoBringToFrontOnFocus + | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; @@ -348,40 +354,40 @@ namespace hex { if (ImGui::BeginMenuBar()) { + auto menuBarHeight = ImGui::GetCurrentWindow()->MenuBarHeight(); + ImGui::SetCursorPosX(5); + ImGui::Image(this->m_logoTexture, ImVec2(menuBarHeight, menuBarHeight)); + for (const auto& menu : { "hex.menu.file"_lang, "hex.menu.edit"_lang, "hex.menu.view"_lang, "hex.menu.help"_lang }) if (ImGui::BeginMenu(menu)) ImGui::EndMenu(); - if (ImGui::BeginMenu("hex.menu.view"_lang)) { - for (auto &view : ContentRegistry::Views::getEntries()) { - if (view->hasViewMenuItemEntry()) - ImGui::MenuItem((LangEntry(view->getUnlocalizedName()) + " " + "hex.menu.view"_lang).c_str(), "", &view->getWindowOpenState()); + if (ImGui::BeginMenu("hex.menu.view"_lang)) { + for (auto &view : ContentRegistry::Views::getEntries()) { + if (view->hasViewMenuItemEntry()) + ImGui::MenuItem((LangEntry(view->getUnlocalizedName()) + " " + "hex.menu.view"_lang).c_str(), "", &view->getWindowOpenState()); + } + ImGui::EndMenu(); } - ImGui::EndMenu(); - } - for (auto &view : ContentRegistry::Views::getEntries()) { - view->drawMenu(); - } + for (auto &view : ContentRegistry::Views::getEntries()) { + view->drawMenu(); + } - if (ImGui::BeginMenu("hex.menu.view"_lang)) { + if (ImGui::BeginMenu("hex.menu.view"_lang)) { #if defined(DEBUG) ImGui::Separator(); ImGui::MenuItem("hex.menu.view.demo"_lang, "", &this->m_demoWindowOpen); #endif - ImGui::EndMenu(); - } + ImGui::EndMenu(); + } - #if defined(DEBUG) - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 2 * ImGui::GetFontSize()); - ImGui::TextUnformatted(ICON_FA_BUG); - #endif + this->drawTitleBar(); - ImGui::EndMenuBar(); + ImGui::EndMenuBar(); } if (SharedData::currentProvider == nullptr) { - char title[256]; + static char title[256]; ImFormatString(title, IM_ARRAYSIZE(title), "%s/DockSpace_%08X", ImGui::GetCurrentWindow()->Name, ImGui::GetID("MainDock")); if (ImGui::Begin(title)) { ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10 * this->m_globalScale, 10 * this->m_globalScale)); @@ -397,9 +403,12 @@ namespace hex { this->resetLayout(); } + this->updateNativeWindow(); + } ImGui::End(); + // Popup for when no plugins were loaded. Intentionally left untranslated because localization isn't available ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F)); if (ImGui::BeginPopupModal("No Plugins", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove)) { @@ -467,12 +476,12 @@ namespace hex { View::drawCommonInterfaces(); -#ifdef DEBUG + #ifdef DEBUG if (this->m_demoWindowOpen) { ImGui::ShowDemoWindow(&this->m_demoWindowOpen); ImPlot::ShowDemoWindow(&this->m_demoWindowOpen); } -#endif + #endif } void Window::frameEnd() { @@ -499,7 +508,7 @@ namespace hex { void Window::drawWelcomeScreen() { const auto availableSpace = ImGui::GetContentRegionAvail(); - ImGui::Image(this->m_bannerTexture, ImVec2(this->m_bannerWidth / (2 * (1.0F / this->m_globalScale)), this->m_bannerHeight / (2 * (1.0F / this->m_globalScale)))); + ImGui::Image(this->m_bannerTexture, this->m_bannerTexture.size() / (2 * (1.0F / this->m_globalScale))); ImGui::Indent(); if (ImGui::BeginTable("Welcome Left", 1, ImGuiTableFlags_NoBordersInBody, ImVec2(availableSpace.x / 2, 0))) { @@ -507,7 +516,7 @@ namespace hex { ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetTextLineHeightWithSpacing() * 3); ImGui::TableNextColumn(); - ImGui::TextWrapped("A Hex Editor for Reverse Engineers, Programmers and people that value their eye sight when working at 3 AM."); + ImGui::TextWrapped("A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM."); ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetTextLineHeightWithSpacing() * 5); ImGui::TableNextColumn(); @@ -663,7 +672,7 @@ namespace hex { throw std::runtime_error("Failed to initialize GLFW!"); #ifdef __APPLE__ - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif if (auto *monitor = glfwGetPrimaryMonitor(); monitor) { @@ -679,7 +688,10 @@ namespace hex { glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - this->m_window = glfwCreateWindow(1280 * this->m_globalScale, 720 * this->m_globalScale, "ImHex", nullptr, nullptr); + this->m_windowTitle = "ImHex"; + this->m_window = glfwCreateWindow(1280 * this->m_globalScale, 720 * this->m_globalScale, this->m_windowTitle.c_str(), nullptr, nullptr); + + this->setupNativeWindow(); glfwSetWindowUserPointer(this->m_window, this); @@ -689,30 +701,35 @@ namespace hex { glfwMakeContextCurrent(this->m_window); glfwSwapInterval(1); - { - int x = 0, y = 0; - glfwGetWindowPos(this->m_window, &x, &y); - SharedData::windowPos = ImVec2(x, y); - } + { + int x = 0, y = 0; + glfwGetWindowPos(this->m_window, &x, &y); + SharedData::windowPos = ImVec2(x, y); + } - { - int width = 0, height = 0; - glfwGetWindowSize(this->m_window, &width, &height); - SharedData::windowSize = ImVec2(width, height); - } + { + int width = 0, height = 0; + glfwGetWindowSize(this->m_window, &width, &height); + glfwSetWindowSize(this->m_window, width, height); + SharedData::windowSize = ImVec2(width, height); + } - glfwSetWindowPosCallback(this->m_window, [](GLFWwindow *window, int x, int y) { - SharedData::windowPos = ImVec2(x, y); + glfwSetWindowPosCallback(this->m_window, [](GLFWwindow *window, int x, int y) { + SharedData::windowPos = ImVec2(x, y); - auto win = static_cast(glfwGetWindowUserPointer(window)); - win->frameBegin(); - win->frame(); - win->frameEnd(); - }); + if (ImGui::GetCurrentContext()->WithinFrameScope) return; + + auto win = static_cast(glfwGetWindowUserPointer(window)); + win->frameBegin(); + win->frame(); + win->frameEnd(); + }); glfwSetWindowSizeCallback(this->m_window, [](GLFWwindow *window, int width, int height) { SharedData::windowSize = ImVec2(width, height); + if (ImGui::GetCurrentContext()->WithinFrameScope) return; + auto win = static_cast(glfwGetWindowUserPointer(window)); win->frameBegin(); win->frame(); @@ -770,7 +787,7 @@ namespace hex { io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard; #if !defined(OS_LINUX) - io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; #endif