From 72cf94106c5326515f70391adf596f65c3adad1b Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sat, 21 Aug 2021 13:55:21 +0200 Subject: [PATCH] ui: Add interface scaling setting. Closes #7, #283 --- .../ImGui/source/imgui_imhex_extensions.cpp | 8 +- include/providers/file_provider.hpp | 4 + include/window.hpp | 2 +- .../source/content/settings_entries.cpp | 19 ++++ plugins/builtin/source/lang/de_DE.cpp | 6 ++ plugins/builtin/source/lang/en_US.cpp | 6 ++ plugins/builtin/source/lang/it_IT.cpp | 6 ++ .../libimhex/include/hex/api/imhex_api.hpp | 8 ++ plugins/libimhex/include/hex/views/view.hpp | 1 + plugins/libimhex/source/api/imhex_api.cpp | 12 +++ plugins/libimhex/source/views/view.cpp | 2 +- source/views/view_hexeditor.cpp | 2 +- source/window/win_window.cpp | 13 ++- source/window/window.cpp | 90 +++++++++++++------ 14 files changed, 140 insertions(+), 39 deletions(-) diff --git a/external/ImGui/source/imgui_imhex_extensions.cpp b/external/ImGui/source/imgui_imhex_extensions.cpp index 76fda3e45..a82524526 100644 --- a/external/ImGui/source/imgui_imhex_extensions.cpp +++ b/external/ImGui/source/imgui_imhex_extensions.cpp @@ -183,14 +183,13 @@ namespace ImGui { void Disabled(const std::function &widgets, bool disabled) { if (disabled) { - ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5F); + BeginDisabled(); widgets(); - ImGui::PopStyleVar(); - ImGui::PopItemFlag(); + EndDisabled(); } else { widgets(); } + } void TextSpinner(const char* label) { @@ -293,6 +292,7 @@ namespace ImGui { if (imageData == nullptr) return { nullptr, -1, -1 }; + GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); diff --git a/include/providers/file_provider.hpp b/include/providers/file_provider.hpp index ee4f4de2e..a50e55ebe 100644 --- a/include/providers/file_provider.hpp +++ b/include/providers/file_provider.hpp @@ -25,6 +25,7 @@ namespace hex::prv { bool isReadable() override; bool isWritable() override; bool isResizable() override; + bool isSavable() override; void read(u64 offset, void *buffer, size_t size, bool overlays) override; void write(u64 offset, const void *buffer, size_t size) override; @@ -34,6 +35,9 @@ namespace hex::prv { void writeRaw(u64 offset, const void *buffer, size_t size) override; size_t getActualSize() override; + void save() override; + void saveAs(const std::string &path) override; + std::vector> getDataInformation() override; private: diff --git a/include/window.hpp b/include/window.hpp index 8ae56be46..1865fd54f 100644 --- a/include/window.hpp +++ b/include/window.hpp @@ -49,7 +49,7 @@ namespace hex { GLFWwindow* m_window = nullptr; - float m_globalScale = 1.0f, m_fontScale = 1.0f; + float m_globalScale = 1.0F, m_fontScale = 1.0F; double m_targetFps = 60.0; bool m_demoWindowOpen = false; bool m_layoutConfigured = false; diff --git a/plugins/builtin/source/content/settings_entries.cpp b/plugins/builtin/source/content/settings_entries.cpp index 9ccb14a84..6b95eacc1 100644 --- a/plugins/builtin/source/content/settings_entries.cpp +++ b/plugins/builtin/source/content/settings_entries.cpp @@ -21,6 +21,25 @@ namespace hex::plugin::builtin { return false; }); + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling", 0, [](auto name, nlohmann::json &setting) { + static int selection = setting.is_number() ? static_cast(setting) : 0; + + const char* scaling[] = { + "hex.builtin.setting.interface.scaling.native"_lang, + "hex.builtin.setting.interface.scaling.x0_5"_lang, + "hex.builtin.setting.interface.scaling.x1_0"_lang, + "hex.builtin.setting.interface.scaling.x1_5"_lang, + "hex.builtin.setting.interface.scaling.x2_0"_lang, + }; + + if (ImGui::Combo(name.data(), &selection, scaling, IM_ARRAYSIZE(scaling))) { + setting = selection; + return true; + } + + return false; + }); + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.language", "en-US", [](auto name, nlohmann::json &setting) { auto &languages = LangEntry::getSupportedLanguages(); diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index be79aced1..70ad22218 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -540,6 +540,12 @@ namespace hex::plugin::builtin { { "hex.builtin.setting.interface.color.dark", "Dunkel" }, { "hex.builtin.setting.interface.color.light", "Hell" }, { "hex.builtin.setting.interface.color.classic", "Klassisch" }, + { "hex.builtin.setting.interface.scaling", "Skalierung" }, + { "hex.builtin.setting.interface.scaling.native", "Nativ" }, + { "hex.builtin.setting.interface.scaling.x0_5", "x0.5" }, + { "hex.builtin.setting.interface.scaling.x1_0", "x1.0" }, + { "hex.builtin.setting.interface.scaling.x1_5", "x1.5" }, + { "hex.builtin.setting.interface.scaling.x2_0", "x2.0" }, { "hex.builtin.setting.interface.language", "Sprache" }, { "hex.builtin.setting.interface.fps", "FPS Limite" }, { "hex.builtin.setting.interface.highlight_alpha", "Markierungssichtbarkeit" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index 360119c1f..e9c7fdb4e 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -541,6 +541,12 @@ namespace hex::plugin::builtin { { "hex.builtin.setting.interface.color.dark", "Dark" }, { "hex.builtin.setting.interface.color.light", "Light" }, { "hex.builtin.setting.interface.color.classic", "Classic" }, + { "hex.builtin.setting.interface.scaling", "Scaling" }, + { "hex.builtin.setting.interface.scaling.native", "Native" }, + { "hex.builtin.setting.interface.scaling.x0_5", "x0.5" }, + { "hex.builtin.setting.interface.scaling.x1_0", "x1.0" }, + { "hex.builtin.setting.interface.scaling.x1_5", "x1.5" }, + { "hex.builtin.setting.interface.scaling.x2_0", "x2.0" }, { "hex.builtin.setting.interface.language", "Language" }, { "hex.builtin.setting.interface.fps", "FPS Limit" }, { "hex.builtin.setting.interface.highlight_alpha", "Highlighting opacity" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 2dd076488..d74657b3b 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -541,6 +541,12 @@ namespace hex::plugin::builtin { { "hex.builtin.setting.interface.color.light", "Chiaro" }, { "hex.builtin.setting.interface.color.classic", "Classico" }, { "hex.builtin.setting.interface.language", "Lingua" }, + //{ "hex.builtin.setting.interface.scaling", "Scaling" }, + //{ "hex.builtin.setting.interface.scaling.native", "Native" }, + //{ "hex.builtin.setting.interface.scaling.x0_5", "x0.5" }, + //{ "hex.builtin.setting.interface.scaling.x1_0", "x1.0" }, + //{ "hex.builtin.setting.interface.scaling.x1_5", "x1.5" }, + //{ "hex.builtin.setting.interface.scaling.x2_0", "x2.0" }, { "hex.builtin.setting.interface.fps", "Limite FPS" }, { "hex.builtin.setting.interface.highlight_alpha", "Evidenziazione dell'opacità" }, diff --git a/plugins/libimhex/include/hex/api/imhex_api.hpp b/plugins/libimhex/include/hex/api/imhex_api.hpp index 01a4f2779..32b82579b 100644 --- a/plugins/libimhex/include/hex/api/imhex_api.hpp +++ b/plugins/libimhex/include/hex/api/imhex_api.hpp @@ -10,6 +10,13 @@ namespace hex { struct ImHexApi { ImHexApi() = delete; + struct Common { + + static void closeImHex(bool noQuestions = false); + static void restartImHex(); + + }; + struct Bookmarks { Bookmarks() = delete; @@ -27,6 +34,7 @@ namespace hex { static std::list& getEntries(); }; + }; } diff --git a/plugins/libimhex/include/hex/views/view.hpp b/plugins/libimhex/include/hex/views/view.hpp index 58f28a457..bdf5a4310 100644 --- a/plugins/libimhex/include/hex/views/view.hpp +++ b/plugins/libimhex/include/hex/views/view.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include diff --git a/plugins/libimhex/source/api/imhex_api.cpp b/plugins/libimhex/source/api/imhex_api.cpp index 6d2c5dad5..40181dd6d 100644 --- a/plugins/libimhex/source/api/imhex_api.cpp +++ b/plugins/libimhex/source/api/imhex_api.cpp @@ -5,6 +5,18 @@ namespace hex { + void ImHexApi::Common::closeImHex(bool noQuestions) { + EventManager::post(noQuestions); + } + + void ImHexApi::Common::restartImHex() { + EventManager::post(false); + std::atexit([]{ + execve(SharedData::mainArgv[0], SharedData::mainArgv, nullptr); + }); + } + + void ImHexApi::Bookmarks::add(Region region, std::string_view name, std::string_view comment, u32 color) { Entry entry; diff --git a/plugins/libimhex/source/views/view.cpp b/plugins/libimhex/source/views/view.cpp index 526150fe5..4a0d10250 100644 --- a/plugins/libimhex/source/views/view.cpp +++ b/plugins/libimhex/source/views/view.cpp @@ -66,7 +66,7 @@ namespace hex { ImGui::NewLine(); ImGui::Separator(); if (ImGui::Button("hex.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape)) { - EventManager::post(); + ImHexApi::Common::closeImHex(); ImGui::CloseCurrentPopup(); } diff --git a/source/views/view_hexeditor.cpp b/source/views/view_hexeditor.cpp index 9819c9030..796910ed0 100644 --- a/source/views/view_hexeditor.cpp +++ b/source/views/view_hexeditor.cpp @@ -286,7 +286,7 @@ namespace hex { ImGui::NewLine(); confirmButtons("hex.common.yes"_lang, "hex.common.no"_lang, [] { - EventManager::post(); + ImHexApi::Common::closeImHex(true); }, [] { ImGui::CloseCurrentPopup(); diff --git a/source/window/win_window.cpp b/source/window/win_window.cpp index b47bd74e1..69a44a6e1 100644 --- a/source/window/win_window.cpp +++ b/source/window/win_window.cpp @@ -18,6 +18,7 @@ static LONG_PTR oldWndProc; static float titleBarHeight; static ImGuiMouseCursor mouseCursorIcon; + static float borderScaling; LRESULT wndProcImHex(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { @@ -72,9 +73,10 @@ 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) + static_cast((::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * borderScaling / 2.0F), + static_cast((::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * borderScaling / 2.0F) }; + RECT window; if (!::GetWindowRect(hwnd, &window)) { return HTNOWHERE; @@ -122,15 +124,19 @@ 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(); + borderScaling = this->m_globalScale; if (mouseCursorIcon != ImGuiMouseCursor_None) ImGui::SetMouseCursor(mouseCursorIcon); @@ -170,8 +176,7 @@ if (ImGui::TitleBarButton(ICON_VS_CHROME_CLOSE, buttonSize)) { - EventManager::post(); - EventManager::post(this->m_window); + ImHexApi::Common::closeImHex(); } ImGui::PopStyleColor(5); diff --git a/source/window/window.cpp b/source/window/window.cpp index 89e19a506..3a7f8fce9 100644 --- a/source/window/window.cpp +++ b/source/window/window.cpp @@ -86,24 +86,24 @@ namespace hex { if (theme.is_number()) { switch (static_cast(theme)) { default: - 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; + 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]; @@ -118,6 +118,19 @@ namespace hex { } } + { + auto scaling = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling"); + + if (scaling.is_number()) { + static bool firstTime = true; + + if (!firstTime) { + ImHexApi::Common::restartImHex(); + } + firstTime = false; + } + } + { auto language = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.language"); @@ -174,8 +187,11 @@ namespace hex { } }); - EventManager::subscribe(this, [this]() { + EventManager::subscribe(this, [this](bool noQuestions) { glfwSetWindowShouldClose(this->m_window, true); + + if (!noQuestions) + EventManager::post(this->m_window); }); EventManager::subscribe(this, [this](std::string windowTitle) { @@ -209,8 +225,6 @@ namespace hex { } } - EventManager::post(); - for (const auto &path : ContentRegistry::Settings::read("hex.builtin.setting.imhex", "hex.builtin.setting.imhex.recent_files")) SharedData::recentFilePaths.push_back(path); @@ -230,6 +244,8 @@ namespace hex { std::signal(SIGFPE, signalHandler); this->m_logoTexture = ImGui::LoadImageFromMemory(imhex_logo, imhex_logo_size); + + EventManager::post(); } Window::~Window() { @@ -441,7 +457,6 @@ namespace hex { ImGui::PopStyleVar(2); - // 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)) { ImGui::TextUnformatted("No ImHex plugins loaded (including the built-in plugin)!"); @@ -707,12 +722,32 @@ namespace hex { glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif + switch (ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling", 0)) { + default: + case 0: + this->m_globalScale = this->m_fontScale = -1.0F; + break; + case 1: + this->m_globalScale = this->m_fontScale = 0.5F; + break; + case 2: + this->m_globalScale = this->m_fontScale = 1.0F; + break; + case 3: + this->m_globalScale = this->m_fontScale = 1.5F; + break; + case 4: + this->m_globalScale = this->m_fontScale = 2.0F; + break; + } + if (auto *monitor = glfwGetPrimaryMonitor(); monitor) { float xscale, yscale; glfwGetMonitorContentScale(monitor, &xscale, &yscale); // In case the horizontal and vertical scale are different, fall back on the average - this->m_globalScale = this->m_fontScale = std::midpoint(xscale, yscale); + if (this->m_globalScale <= 0.0F) + this->m_globalScale = this->m_fontScale = std::midpoint(xscale, yscale); } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); @@ -749,7 +784,7 @@ namespace hex { glfwSetWindowPosCallback(this->m_window, [](GLFWwindow *window, int x, int y) { SharedData::windowPos = ImVec2(x, y); - if (ImGui::GetCurrentContext()->WithinFrameScope) return; + if (auto g = ImGui::GetCurrentContext(); g == nullptr || g->WithinFrameScope) return; auto win = static_cast(glfwGetWindowUserPointer(window)); win->frameBegin(); @@ -760,7 +795,7 @@ namespace hex { glfwSetWindowSizeCallback(this->m_window, [](GLFWwindow *window, int width, int height) { SharedData::windowSize = ImVec2(width, height); - if (ImGui::GetCurrentContext()->WithinFrameScope) return; + if (auto g = ImGui::GetCurrentContext(); g == nullptr || g->WithinFrameScope) return; auto win = static_cast(glfwGetWindowUserPointer(window)); win->frameBegin(); @@ -801,7 +836,7 @@ namespace hex { EventManager::post(window); }); - glfwSetWindowSizeLimits(this->m_window, 720, 480, GLFW_DONT_CARE, GLFW_DONT_CARE); + glfwSetWindowSizeLimits(this->m_window, 720 * this->m_globalScale, 480 * this->m_globalScale, GLFW_DONT_CARE, GLFW_DONT_CARE); if (gladLoadGL() == 0) throw std::runtime_error("Failed to initialize OpenGL loader!"); @@ -860,8 +895,7 @@ namespace hex { io.UserData = new ImGui::ImHexCustomData(); - if (this->m_globalScale != 0.0f) - style.ScaleAllSizes(this->m_globalScale); + style.ScaleAllSizes(this->m_globalScale); std::string fontFile; for (const auto &dir : hex::getPath(ImHexPath::Resources)) {