2020-11-10 15:26:38 +01:00
|
|
|
#include "window.hpp"
|
|
|
|
|
2020-12-22 18:10:01 +01:00
|
|
|
#include <hex.hpp>
|
2021-08-29 22:15:18 +02:00
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
#include <hex/api/plugin_manager.hpp>
|
|
|
|
#include <hex/api/content_registry.hpp>
|
|
|
|
#include <hex/api/imhex_api.hpp>
|
2023-05-11 18:44:50 +02:00
|
|
|
#include <hex/api/layout_manager.hpp>
|
2023-11-18 14:50:43 +01:00
|
|
|
#include <hex/api/shortcut_manager.hpp>
|
2023-12-11 15:54:22 +01:00
|
|
|
#include <hex/api/workspace_manager.hpp>
|
|
|
|
#include <hex/api/project_file_manager.hpp>
|
2023-12-13 11:24:25 +01:00
|
|
|
#include <hex/api/tutorial_manager.hpp>
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2021-08-29 22:15:18 +02:00
|
|
|
#include <hex/helpers/utils.hpp>
|
2022-03-04 11:36:37 +01:00
|
|
|
#include <hex/helpers/fs.hpp>
|
2021-08-29 22:15:18 +02:00
|
|
|
#include <hex/helpers/logger.hpp>
|
2020-12-22 18:10:01 +01:00
|
|
|
|
2023-04-07 10:21:27 +02:00
|
|
|
#include <hex/ui/view.hpp>
|
|
|
|
#include <hex/ui/popup.hpp>
|
|
|
|
|
2021-03-06 13:09:20 +01:00
|
|
|
#include <chrono>
|
2021-08-17 13:41:44 +02:00
|
|
|
#include <csignal>
|
2020-11-10 15:26:38 +01:00
|
|
|
|
2021-12-22 15:06:16 +01:00
|
|
|
#include <romfs/romfs.hpp>
|
|
|
|
|
2021-01-13 17:28:27 +01:00
|
|
|
#include <imgui.h>
|
|
|
|
#include <imgui_internal.h>
|
|
|
|
#include <imgui_impl_glfw.h>
|
|
|
|
#include <imgui_impl_opengl3.h>
|
2021-12-31 01:10:06 +01:00
|
|
|
#include <hex/ui/imgui_imhex_extensions.h>
|
2021-03-02 13:48:23 +01:00
|
|
|
#include <implot.h>
|
|
|
|
#include <implot_internal.h>
|
2021-08-17 13:41:19 +02:00
|
|
|
#include <imnodes.h>
|
|
|
|
#include <imnodes_internal.h>
|
2020-11-10 15:26:38 +01:00
|
|
|
|
2023-07-09 12:53:31 +02:00
|
|
|
#include <wolv/utils/string.hpp>
|
|
|
|
|
2022-07-26 14:59:08 +02:00
|
|
|
#include <fonts/codicons_font.h>
|
2021-02-24 22:42:26 +01:00
|
|
|
|
2020-11-10 15:26:38 +01:00
|
|
|
#include <GLFW/glfw3.h>
|
2023-12-19 23:21:20 +01:00
|
|
|
#include <hex/ui/toast.hpp>
|
2024-01-06 17:38:55 +01:00
|
|
|
#include <wolv/utils/guards.hpp>
|
2021-08-29 14:18:45 +02:00
|
|
|
|
2020-11-10 15:26:38 +01:00
|
|
|
namespace hex {
|
|
|
|
|
2021-03-06 13:09:20 +01:00
|
|
|
using namespace std::literals::chrono_literals;
|
|
|
|
|
2022-02-15 23:07:48 +01:00
|
|
|
Window::Window() {
|
2023-01-31 11:38:26 +01:00
|
|
|
constexpr static auto openEmergencyPopup = [](const std::string &title){
|
|
|
|
TaskManager::doLater([title] {
|
|
|
|
for (const auto &provider : ImHexApi::Provider::getProviders())
|
|
|
|
ImHexApi::Provider::remove(provider, false);
|
|
|
|
|
|
|
|
ImGui::OpenPopup(title.c_str());
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Handle fatal error popups for errors detected during initialization
|
2021-04-18 20:24:42 +02:00
|
|
|
{
|
2022-02-01 18:09:40 +01:00
|
|
|
for (const auto &[argument, value] : ImHexApi::System::getInitArguments()) {
|
|
|
|
if (argument == "no-plugins") {
|
2023-01-31 11:38:26 +01:00
|
|
|
openEmergencyPopup("No Plugins");
|
2022-02-01 23:57:48 +01:00
|
|
|
} else if (argument == "no-builtin-plugin") {
|
2023-01-31 11:38:26 +01:00
|
|
|
openEmergencyPopup("No Builtin Plugin");
|
2022-02-01 23:57:48 +01:00
|
|
|
} else if (argument == "multiple-builtin-plugins") {
|
2023-01-31 11:38:26 +01:00
|
|
|
openEmergencyPopup("Multiple Builtin Plugins");
|
2021-04-18 20:24:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-04-17 15:46:26 +02:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Initialize the window
|
2020-11-10 15:26:38 +01:00
|
|
|
this->initGLFW();
|
|
|
|
this->initImGui();
|
2021-11-28 11:57:52 +01:00
|
|
|
this->setupNativeWindow();
|
2023-02-17 12:03:53 +01:00
|
|
|
this->registerEventHandlers();
|
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
m_logoTexture = ImGuiExt::Texture(romfs::get("logo.png").span(), ImGuiExt::Texture::Filter::Linear);
|
2023-02-17 12:03:53 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
ContentRegistry::Settings::impl::store();
|
2023-12-08 10:29:44 +01:00
|
|
|
EventSettingsChanged::post();
|
|
|
|
EventWindowInitialized::post();
|
|
|
|
EventImHexStartupFinished::post();
|
2023-02-17 12:03:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Window::~Window() {
|
2023-12-08 10:29:44 +01:00
|
|
|
EventProviderDeleted::unsubscribe(this);
|
|
|
|
RequestCloseImHex::unsubscribe(this);
|
|
|
|
RequestUpdateWindowTitle::unsubscribe(this);
|
|
|
|
EventAbnormalTermination::unsubscribe(this);
|
|
|
|
RequestOpenPopup::unsubscribe(this);
|
2023-02-17 12:03:53 +01:00
|
|
|
|
2023-12-11 15:54:22 +01:00
|
|
|
WorkspaceManager::exportToFile();
|
2023-12-20 16:31:31 +01:00
|
|
|
|
|
|
|
if (auto workspace = WorkspaceManager::getCurrentWorkspace(); workspace != WorkspaceManager::getWorkspaces().end())
|
|
|
|
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.curr_workspace", workspace->first);
|
2023-12-11 15:54:22 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
this->exitImGui();
|
|
|
|
this->exitGLFW();
|
|
|
|
}
|
2021-01-31 00:04:33 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
void Window::registerEventHandlers() {
|
2022-08-09 16:29:52 +02:00
|
|
|
// Initialize default theme
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestChangeTheme::post("Dark");
|
2022-08-09 16:29:52 +02:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Handle the close window request by telling GLFW to shut down
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestCloseImHex::subscribe(this, [this](bool noQuestions) {
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowShouldClose(m_window, GLFW_TRUE);
|
2021-08-21 13:55:21 +02:00
|
|
|
|
|
|
|
if (!noQuestions)
|
2023-12-19 13:10:25 +01:00
|
|
|
EventWindowClosing::post(m_window);
|
2021-02-01 19:03:45 +01:00
|
|
|
});
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Handle updating the window title
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestUpdateWindowTitle::subscribe(this, [this] {
|
2023-12-14 13:50:26 +01:00
|
|
|
std::string prefix, postfix;
|
2021-08-17 13:41:44 +02:00
|
|
|
std::string title = "ImHex";
|
|
|
|
|
2023-01-07 17:31:22 +01:00
|
|
|
if (ProjectFile::hasPath()) {
|
2023-02-17 12:03:53 +01:00
|
|
|
// If a project is open, show the project name instead of the file name
|
|
|
|
|
2023-12-14 13:50:26 +01:00
|
|
|
prefix = "Project ";
|
|
|
|
title = ProjectFile::getPath().stem().string();
|
2023-01-07 17:31:22 +01:00
|
|
|
|
|
|
|
if (ImHexApi::Provider::isDirty())
|
2023-12-14 13:50:26 +01:00
|
|
|
postfix += " (*)";
|
2023-01-07 17:31:22 +01:00
|
|
|
|
|
|
|
} else if (ImHexApi::Provider::isValid()) {
|
2022-08-08 21:23:52 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2023-01-07 17:31:22 +01:00
|
|
|
if (provider != nullptr) {
|
2023-12-14 13:50:26 +01:00
|
|
|
title = provider->getName();
|
2021-09-08 15:18:24 +02:00
|
|
|
|
2022-08-22 11:00:31 +02:00
|
|
|
if (provider->isDirty())
|
2023-12-14 13:50:26 +01:00
|
|
|
postfix += " (*)";
|
2022-02-16 10:04:05 +01:00
|
|
|
|
2023-12-18 11:58:19 +01:00
|
|
|
if (!provider->isWritable() && provider->getActualSize() != 0)
|
2023-12-14 13:50:26 +01:00
|
|
|
postfix += " (Read Only)";
|
2022-08-22 11:00:31 +02:00
|
|
|
}
|
2021-09-08 15:18:24 +02:00
|
|
|
}
|
2021-08-17 13:41:44 +02:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
m_windowTitle = prefix + hex::limitStringLength(title, 32) + postfix;
|
|
|
|
m_windowTitleFull = prefix + title + postfix;
|
2023-05-15 11:30:24 +02:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
if (m_window != nullptr) {
|
2023-12-07 11:19:08 +01:00
|
|
|
if (title != "ImHex")
|
|
|
|
title = "ImHex - " + title;
|
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowTitle(m_window, title.c_str());
|
2023-12-07 11:19:08 +01:00
|
|
|
}
|
2021-08-17 13:41:44 +02:00
|
|
|
});
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Handle opening popups
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestOpenPopup::subscribe(this, [this](auto name) {
|
2023-12-19 13:10:25 +01:00
|
|
|
std::scoped_lock lock(m_popupMutex);
|
2022-09-19 16:09:22 +02:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
m_popupsToOpen.push_back(name);
|
2021-09-26 21:18:25 +02:00
|
|
|
});
|
2020-11-10 15:26:38 +01:00
|
|
|
}
|
|
|
|
|
2023-09-07 20:33:49 +02:00
|
|
|
void Window::fullFrame() {
|
2023-12-19 13:10:25 +01:00
|
|
|
m_lastStartFrameTime = glfwGetTime();
|
2023-10-04 12:00:32 +02:00
|
|
|
|
2023-09-07 20:33:49 +02:00
|
|
|
glfwPollEvents();
|
|
|
|
|
|
|
|
// Render frame
|
|
|
|
this->frameBegin();
|
|
|
|
this->frame();
|
|
|
|
this->frameEnd();
|
|
|
|
}
|
|
|
|
|
2020-11-10 15:26:38 +01:00
|
|
|
void Window::loop() {
|
2023-12-19 13:10:25 +01:00
|
|
|
while (!glfwWindowShouldClose(m_window)) {
|
|
|
|
m_lastStartFrameTime = glfwGetTime();
|
2023-05-11 23:22:06 +02:00
|
|
|
|
2024-01-02 17:11:52 +01:00
|
|
|
// Determine if the application should be in long sleep mode
|
2023-12-27 13:54:00 +01:00
|
|
|
bool shouldLongSleep = !m_unlockFrameRate;
|
|
|
|
|
2024-01-02 17:11:52 +01:00
|
|
|
// Wait 5 frames before actually enabling the long sleep mode to make animations not stutter
|
|
|
|
constexpr static auto LongSleepTimeout = 5;
|
2023-12-27 13:54:00 +01:00
|
|
|
static i32 lockTimeout = 0;
|
|
|
|
if (!shouldLongSleep) {
|
2024-01-02 17:11:52 +01:00
|
|
|
lockTimeout = LongSleepTimeout;
|
2023-12-27 13:54:00 +01:00
|
|
|
} else if (lockTimeout > 0) {
|
|
|
|
lockTimeout -= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shouldLongSleep && lockTimeout > 0)
|
|
|
|
shouldLongSleep = false;
|
|
|
|
|
|
|
|
m_unlockFrameRate = false;
|
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
if (!glfwGetWindowAttrib(m_window, GLFW_VISIBLE) || glfwGetWindowAttrib(m_window, GLFW_ICONIFIED)) {
|
2023-02-17 12:03:53 +01:00
|
|
|
// If the application is minimized or not visible, don't render anything
|
2021-06-07 18:14:40 +02:00
|
|
|
glfwWaitEvents();
|
2021-12-16 23:48:52 +01:00
|
|
|
} else {
|
2024-01-02 17:11:52 +01:00
|
|
|
// If the application is visible, render a frame
|
|
|
|
|
|
|
|
// If the application is in long sleep mode, only render a frame every 200ms
|
|
|
|
// Long sleep mode is enabled automatically after a few frames if the window content hasn't changed
|
|
|
|
// and no events have been received
|
|
|
|
if (shouldLongSleep) {
|
2023-08-11 22:03:30 +02:00
|
|
|
// Calculate the time until the next frame
|
2024-01-02 17:11:52 +01:00
|
|
|
constexpr static auto LongSleepFPS = 5.0;
|
|
|
|
const double timeout = std::max(0.0, (1.0 / LongSleepFPS) - (glfwGetTime() - m_lastStartFrameTime));
|
2023-02-17 12:03:53 +01:00
|
|
|
|
2024-01-02 17:11:52 +01:00
|
|
|
glfwWaitEventsTimeout(timeout);
|
2022-08-03 23:32:34 +02:00
|
|
|
}
|
2021-12-16 23:48:52 +01:00
|
|
|
}
|
|
|
|
|
2023-09-07 20:33:49 +02:00
|
|
|
this->fullFrame();
|
2023-08-11 22:03:30 +02:00
|
|
|
|
2023-12-20 13:42:42 +01:00
|
|
|
ImHexApi::System::impl::setLastFrameTime(glfwGetTime() - m_lastStartFrameTime);
|
|
|
|
|
2023-08-11 22:03:30 +02:00
|
|
|
// Limit frame rate
|
|
|
|
// If the target FPS are below 15, use the monitor refresh rate, if it's above 200, don't limit the frame rate
|
|
|
|
const auto targetFPS = ImHexApi::System::getTargetFPS();
|
|
|
|
if (targetFPS < 15) {
|
|
|
|
glfwSwapInterval(1);
|
|
|
|
} else if (targetFPS > 200) {
|
|
|
|
glfwSwapInterval(0);
|
|
|
|
} else {
|
2023-12-27 13:54:00 +01:00
|
|
|
if (!shouldLongSleep) {
|
2023-12-20 12:07:22 +01:00
|
|
|
glfwSwapInterval(0);
|
|
|
|
const auto frameTime = glfwGetTime() - m_lastStartFrameTime;
|
|
|
|
const auto targetFrameTime = 1.0 / targetFPS;
|
|
|
|
if (frameTime < targetFrameTime) {
|
|
|
|
glfwWaitEventsTimeout(targetFrameTime - frameTime);
|
|
|
|
}
|
2023-08-11 22:03:30 +02:00
|
|
|
}
|
|
|
|
}
|
2023-12-11 11:42:33 +01:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
m_lastFrameTime = glfwGetTime() - m_lastStartFrameTime;
|
2020-11-10 15:26:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-08 21:51:48 +01:00
|
|
|
static void createNestedMenu(std::span<const UnlocalizedString> menuItems, const char *icon, const Shortcut &shortcut, const std::function<void()> &callback, const std::function<bool()> &enabledCallback) {
|
2023-03-20 13:11:43 +01:00
|
|
|
const auto &name = menuItems.front();
|
|
|
|
|
2023-12-19 12:22:28 +01:00
|
|
|
if (name.get() == ContentRegistry::Interface::impl::SeparatorValue) {
|
2023-03-20 13:11:43 +01:00
|
|
|
ImGui::Separator();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-19 12:22:28 +01:00
|
|
|
if (name.get() == ContentRegistry::Interface::impl::SubMenuValue) {
|
2023-03-20 13:11:43 +01:00
|
|
|
callback();
|
|
|
|
} else if (menuItems.size() == 1) {
|
2024-01-08 21:51:48 +01:00
|
|
|
if (ImGui::MenuItemEx(Lang(name), icon, shortcut.toString().c_str(), false, enabledCallback()))
|
2023-03-20 13:11:43 +01:00
|
|
|
callback();
|
|
|
|
} else {
|
2023-12-19 12:22:28 +01:00
|
|
|
bool isSubmenu = (menuItems.begin() + 1)->get() == ContentRegistry::Interface::impl::SubMenuValue;
|
2023-11-24 20:57:37 +01:00
|
|
|
|
2024-01-08 21:51:48 +01:00
|
|
|
if (ImGui::BeginMenuEx(Lang(name), std::next(menuItems.begin())->get() == ContentRegistry::Interface::impl::SubMenuValue ? icon : nullptr, isSubmenu ? enabledCallback() : true)) {
|
|
|
|
createNestedMenu({ std::next(menuItems.begin()), menuItems.end() }, icon, shortcut, callback, enabledCallback);
|
2023-03-20 13:11:43 +01:00
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-31 11:39:06 +01:00
|
|
|
void Window::drawTitleBar() {
|
2023-12-18 10:14:07 +01:00
|
|
|
auto titleBarHeight = ImGui::GetCurrentWindowRead()->MenuBarHeight();
|
2023-05-25 09:26:40 +02:00
|
|
|
auto buttonSize = ImVec2(titleBarHeight * 1.5F, titleBarHeight - 1);
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
2023-12-06 11:05:02 +01:00
|
|
|
const auto windowSize = ImHexApi::System::getMainWindowSize();
|
2023-12-31 11:39:06 +01:00
|
|
|
const auto searchBoxSize = ImVec2(windowSize.x / 2.5, titleBarHeight - 3_scaled);
|
2023-12-06 11:05:02 +01:00
|
|
|
const auto searchBoxPos = ImVec2((windowSize / 2 - searchBoxSize / 2).x, 3_scaled);
|
|
|
|
|
2023-12-31 11:39:06 +01:00
|
|
|
m_searchBarPosition = searchBoxPos.x;
|
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
// Custom titlebar buttons implementation for borderless window mode
|
2023-05-25 09:26:40 +02:00
|
|
|
auto &titleBarButtons = ContentRegistry::Interface::impl::getTitleBarButtons();
|
|
|
|
|
|
|
|
// Draw custom title bar buttons
|
2023-11-10 20:47:08 +01:00
|
|
|
if (!titleBarButtons.empty()) {
|
|
|
|
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * float(4 + titleBarButtons.size()));
|
2023-12-06 11:05:02 +01:00
|
|
|
|
|
|
|
if (ImGui::GetCursorPosX() > (searchBoxPos.x + searchBoxSize.x)) {
|
|
|
|
for (const auto &[icon, tooltip, callback]: titleBarButtons) {
|
|
|
|
if (ImGuiExt::TitleBarButton(icon.c_str(), buttonSize)) {
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
ImGuiExt::InfoTooltip(Lang(tooltip));
|
2023-08-13 23:54:22 +02:00
|
|
|
}
|
2023-05-25 09:26:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-06 11:05:02 +01:00
|
|
|
if (ImHexApi::System::isBorderlessWindowModeEnabled()) {
|
|
|
|
// Draw minimize, restore and maximize buttons
|
|
|
|
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * 3);
|
|
|
|
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_MINIMIZE, buttonSize))
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwIconifyWindow(m_window);
|
|
|
|
if (glfwGetWindowAttrib(m_window, GLFW_MAXIMIZED)) {
|
2023-12-06 11:05:02 +01:00
|
|
|
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_RESTORE, buttonSize))
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwRestoreWindow(m_window);
|
2023-12-06 11:05:02 +01:00
|
|
|
} else {
|
|
|
|
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_MAXIMIZE, buttonSize))
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwMaximizeWindow(m_window);
|
2023-12-06 11:05:02 +01:00
|
|
|
}
|
impr: Don't force using discrete graphics card on macOS (#1341)
<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->
### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
When starting ImHex on a MacBook model with both integrated and discrete
graphics, it will force the computer to use the discrete graphics card.
This causes increased power usage, meaning the fans will spin up, the
battery will drain faster, etc. This program is not very graphics
intensive, so using the discrete graphics card shouldn't be needed.
### Implementation description
<!-- Explain what you did to correct the problem -->
I changed the
[`GLFW_COCOA_GRAPHICS_SWITCHING`](https://www.glfw.org/docs/latest/window_guide.html#window_hints_osx)
setting in GLFW to not enforce using the discrete graphics.
### Screenshots
<!-- If your change is visual, take a screenshot showing it. Ideally,
make before/after sceenshots -->
### Additional things
<!-- Anything else you would like to say -->
My editor is configured to automatically remove trailing whitespace, so
I hope that those whitespace changes are ok
2023-10-05 08:39:53 +02:00
|
|
|
|
2023-12-06 11:05:02 +01:00
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xFF7A70F1);
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF2311E8);
|
2023-05-25 09:26:40 +02:00
|
|
|
|
2023-12-06 11:05:02 +01:00
|
|
|
// Draw close button
|
|
|
|
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_CLOSE, buttonSize)) {
|
|
|
|
ImHexApi::System::closeImHex();
|
|
|
|
}
|
2023-05-25 09:26:40 +02:00
|
|
|
|
2023-12-06 11:05:02 +01:00
|
|
|
ImGui::PopStyleColor(2);
|
2023-05-25 09:26:40 +02:00
|
|
|
}
|
|
|
|
|
2023-12-06 11:05:02 +01:00
|
|
|
ImGui::PopStyleColor(3);
|
2023-05-25 09:26:40 +02:00
|
|
|
ImGui::PopStyleVar();
|
|
|
|
|
2023-11-14 00:03:22 +01:00
|
|
|
{
|
|
|
|
const auto buttonColor = [](float alpha) {
|
|
|
|
return ImU32(ImColor(ImGui::GetStyleColorVec4(ImGuiCol_DockingEmptyBg) * ImVec4(1, 1, 1, alpha)));
|
|
|
|
};
|
|
|
|
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor(0.5F));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonColor(0.7F));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, buttonColor(0.9F));
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0_scaled);
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4_scaled);
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, scaled({ 1, 1 }));
|
|
|
|
|
|
|
|
ImGui::SetCursorPos(searchBoxPos);
|
2023-12-19 13:10:25 +01:00
|
|
|
if (ImGui::Button(m_windowTitle.c_str(), searchBoxSize)) {
|
2023-12-14 13:50:26 +01:00
|
|
|
EventSearchBoxClicked::post(ImGuiMouseButton_Left);
|
2023-11-14 00:03:22 +01:00
|
|
|
}
|
|
|
|
|
2023-12-14 13:50:26 +01:00
|
|
|
if (ImGui::IsItemClicked(ImGuiMouseButton_Right))
|
|
|
|
EventSearchBoxClicked::post(ImGuiMouseButton_Right);
|
|
|
|
|
|
|
|
ImGui::PushTextWrapPos(300_scaled);
|
2023-12-19 13:10:25 +01:00
|
|
|
if (!m_windowTitleFull.empty())
|
|
|
|
ImGui::SetItemTooltip("%s", m_windowTitleFull.c_str());
|
2023-12-14 13:50:26 +01:00
|
|
|
ImGui::PopTextWrapPos();
|
|
|
|
|
2023-11-14 00:03:22 +01:00
|
|
|
ImGui::PopStyleVar(3);
|
|
|
|
ImGui::PopStyleColor(3);
|
|
|
|
}
|
2023-05-25 09:26:40 +02:00
|
|
|
}
|
impr: Don't force using discrete graphics card on macOS (#1341)
<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->
### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
When starting ImHex on a MacBook model with both integrated and discrete
graphics, it will force the computer to use the discrete graphics card.
This causes increased power usage, meaning the fans will spin up, the
battery will drain faster, etc. This program is not very graphics
intensive, so using the discrete graphics card shouldn't be needed.
### Implementation description
<!-- Explain what you did to correct the problem -->
I changed the
[`GLFW_COCOA_GRAPHICS_SWITCHING`](https://www.glfw.org/docs/latest/window_guide.html#window_hints_osx)
setting in GLFW to not enforce using the discrete graphics.
### Screenshots
<!-- If your change is visual, take a screenshot showing it. Ideally,
make before/after sceenshots -->
### Additional things
<!-- Anything else you would like to say -->
My editor is configured to automatically remove trailing whitespace, so
I hope that those whitespace changes are ok
2023-10-05 08:39:53 +02:00
|
|
|
|
2023-11-07 16:40:37 +01:00
|
|
|
static bool isAnyViewOpen() {
|
|
|
|
const auto &views = ContentRegistry::Views::impl::getEntries();
|
|
|
|
return std::any_of(views.begin(), views.end(),
|
|
|
|
[](const auto &entry) {
|
|
|
|
return entry.second->getWindowOpenState();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-11-10 15:26:38 +01:00
|
|
|
void Window::frameBegin() {
|
2023-02-17 12:03:53 +01:00
|
|
|
// Start new ImGui Frame
|
2020-11-10 15:26:38 +01:00
|
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
|
|
ImGui_ImplGlfw_NewFrame();
|
|
|
|
ImGui::NewFrame();
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Handle all undocked floating windows
|
2022-01-24 20:53:17 +01:00
|
|
|
ImGuiViewport *viewport = ImGui::GetMainViewport();
|
2022-07-07 07:16:38 +02:00
|
|
|
ImGui::SetNextWindowPos(viewport->WorkPos);
|
2022-07-06 10:21:38 +02:00
|
|
|
ImGui::SetNextWindowSize(ImHexApi::System::getMainWindowSize() - ImVec2(0, ImGui::GetTextLineHeightWithSpacing()));
|
2020-11-10 15:26:38 +01:00
|
|
|
ImGui::SetNextWindowViewport(viewport->ID);
|
2023-05-11 23:56:51 +02:00
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0F);
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F);
|
2021-08-21 00:52:11 +02:00
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
2020-11-30 00:03:12 +01:00
|
|
|
|
2022-01-24 20:53:17 +01:00
|
|
|
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
|
2020-11-10 15:26:38 +01:00
|
|
|
|
2021-01-21 17:48:24 +01:00
|
|
|
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Render main dock space
|
2022-02-06 21:39:10 +01:00
|
|
|
if (ImGui::Begin("ImHexDockSpace", nullptr, windowFlags)) {
|
2022-01-22 22:03:19 +01:00
|
|
|
auto drawList = ImGui::GetWindowDrawList();
|
2021-08-21 00:52:11 +02:00
|
|
|
ImGui::PopStyleVar();
|
2023-11-08 11:53:26 +01:00
|
|
|
|
2023-11-14 16:09:26 +01:00
|
|
|
bool shouldDrawSidebar = [] {
|
2023-12-27 16:33:49 +01:00
|
|
|
if (const auto &items = ContentRegistry::Interface::impl::getSidebarItems(); items.empty()) {
|
2023-11-14 16:09:26 +01:00
|
|
|
return false;
|
2023-12-27 16:33:49 +01:00
|
|
|
} else {
|
2023-11-14 16:09:26 +01:00
|
|
|
return std::any_of(items.begin(), items.end(), [](const auto &item) {
|
|
|
|
return item.enabledCallback();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}();
|
|
|
|
|
2023-12-18 10:14:07 +01:00
|
|
|
const auto menuBarHeight = ImGui::GetCurrentWindowRead()->MenuBarHeight();
|
2023-12-07 23:47:25 +01:00
|
|
|
auto sidebarPos = ImGui::GetCursorPos();
|
2023-11-14 16:09:26 +01:00
|
|
|
auto sidebarWidth = shouldDrawSidebar ? 20_scaled : 0;
|
2022-01-22 22:03:19 +01:00
|
|
|
|
|
|
|
ImGui::SetCursorPosX(sidebarWidth);
|
|
|
|
|
2022-02-01 22:09:44 +01:00
|
|
|
auto footerHeight = ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().FramePadding.y * 2 + 1_scaled;
|
2022-02-01 18:09:40 +01:00
|
|
|
auto dockSpaceSize = ImVec2(ImHexApi::System::getMainWindowSize().x - sidebarWidth, ImGui::GetContentRegionAvail().y - footerHeight);
|
2022-01-22 22:03:19 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Render footer
|
|
|
|
{
|
2022-01-22 22:03:19 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
auto dockId = ImGui::DockSpace(ImGui::GetID("ImHexMainDock"), dockSpaceSize);
|
|
|
|
ImHexApi::System::impl::setMainDockSpaceId(dockId);
|
2021-02-18 12:09:19 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
drawList->AddRectFilled(ImGui::GetWindowPos(), ImGui::GetWindowPos() + ImGui::GetWindowSize() - ImVec2(dockSpaceSize.x, footerHeight - ImGui::GetStyle().FramePadding.y - 1_scaled), ImGui::GetColorU32(ImGuiCol_MenuBarBg));
|
2020-11-10 15:26:38 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
ImGui::Separator();
|
|
|
|
ImGui::SetCursorPosX(8);
|
2023-03-21 15:33:43 +01:00
|
|
|
for (const auto &callback : ContentRegistry::Interface::impl::getFooterItems()) {
|
2023-02-17 12:03:53 +01:00
|
|
|
auto prevIdx = drawList->_VtxCurrentIdx;
|
|
|
|
callback();
|
|
|
|
auto currIdx = drawList->_VtxCurrentIdx;
|
|
|
|
|
|
|
|
// Only draw separator if something was actually drawn
|
|
|
|
if (prevIdx != currIdx) {
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
|
|
|
ImGui::SameLine();
|
|
|
|
}
|
2022-08-04 11:00:49 +02:00
|
|
|
}
|
2021-02-18 12:09:19 +01:00
|
|
|
}
|
2021-02-11 23:09:45 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Render sidebar
|
2023-11-14 16:09:26 +01:00
|
|
|
if (shouldDrawSidebar) {
|
2022-01-22 22:03:19 +01:00
|
|
|
ImGui::SetCursorPos(sidebarPos);
|
|
|
|
|
2022-01-22 22:37:52 +01:00
|
|
|
static i32 openWindow = -1;
|
2023-11-07 16:40:37 +01:00
|
|
|
u32 index = 0;
|
2022-01-22 22:03:19 +01:00
|
|
|
ImGui::PushID("SideBarWindows");
|
2023-11-14 15:55:25 +01:00
|
|
|
for (const auto &[icon, callback, enabledCallback] : ContentRegistry::Interface::impl::getSidebarItems()) {
|
2022-01-22 22:03:19 +01:00
|
|
|
ImGui::SetCursorPosY(sidebarPos.y + sidebarWidth * index);
|
|
|
|
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_MenuBarBg));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabActive));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabHovered));
|
|
|
|
|
2023-11-14 15:55:25 +01:00
|
|
|
ImGui::BeginDisabled(!(ImHexApi::Provider::isValid() && enabledCallback()));
|
2022-01-22 22:03:19 +01:00
|
|
|
{
|
|
|
|
if (ImGui::Button(icon.c_str(), ImVec2(sidebarWidth, sidebarWidth))) {
|
2022-03-27 00:01:28 +01:00
|
|
|
if (static_cast<u32>(openWindow) == index)
|
2022-01-22 22:03:19 +01:00
|
|
|
openWindow = -1;
|
|
|
|
else
|
|
|
|
openWindow = index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ImGui::EndDisabled();
|
|
|
|
|
|
|
|
ImGui::PopStyleColor(3);
|
|
|
|
|
2023-11-08 11:53:26 +01:00
|
|
|
auto sideBarFocused = ImGui::IsWindowFocused();
|
|
|
|
|
2022-03-27 00:01:28 +01:00
|
|
|
bool open = static_cast<u32>(openWindow) == index;
|
2022-01-22 22:03:19 +01:00
|
|
|
if (open) {
|
2023-11-14 15:55:25 +01:00
|
|
|
|
2023-11-08 11:53:26 +01:00
|
|
|
ImGui::SetNextWindowPos(ImGui::GetWindowPos() + sidebarPos + ImVec2(sidebarWidth - 1_scaled, -1_scaled));
|
2023-12-07 23:47:25 +01:00
|
|
|
ImGui::SetNextWindowSize(ImVec2(0, dockSpaceSize.y + 5_scaled));
|
2022-01-22 22:03:19 +01:00
|
|
|
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1);
|
2023-11-27 15:34:05 +01:00
|
|
|
ImGui::PushStyleColor(ImGuiCol_WindowShadow, 0x00000000);
|
2023-12-07 23:47:25 +01:00
|
|
|
if (ImGui::Begin("SideBarWindow", &open, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
|
|
|
if (ImGui::BeginChild("##Content", ImVec2(), ImGuiChildFlags_ResizeX)) {
|
2023-11-14 15:55:25 +01:00
|
|
|
callback();
|
|
|
|
}
|
2023-12-07 23:47:25 +01:00
|
|
|
ImGui::EndChild();
|
2023-11-08 11:53:26 +01:00
|
|
|
|
2023-11-14 15:55:25 +01:00
|
|
|
if (!ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && !sideBarFocused) {
|
2023-11-08 11:53:26 +01:00
|
|
|
openWindow = -1;
|
|
|
|
}
|
2022-01-22 22:03:19 +01:00
|
|
|
}
|
|
|
|
ImGui::End();
|
|
|
|
ImGui::PopStyleVar();
|
2023-11-27 15:34:05 +01:00
|
|
|
ImGui::PopStyleColor();
|
2022-01-22 22:03:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::NewLine();
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
ImGui::PopID();
|
|
|
|
}
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Render main menu
|
2023-05-02 20:35:30 +02:00
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F);
|
2023-07-01 22:55:59 +02:00
|
|
|
ImGui::SetNextWindowScroll(ImVec2(0, 0));
|
2021-08-21 00:52:11 +02:00
|
|
|
if (ImGui::BeginMainMenuBar()) {
|
2021-02-18 12:09:19 +01:00
|
|
|
|
2022-02-15 23:07:48 +01:00
|
|
|
if (ImHexApi::System::isBorderlessWindowModeEnabled()) {
|
2022-02-15 22:36:36 +01:00
|
|
|
ImGui::SetCursorPosX(5);
|
2023-08-19 19:12:15 +02:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
ImGui::Image(m_logoTexture, ImVec2(menuBarHeight, menuBarHeight));
|
2023-08-19 19:12:15 +02:00
|
|
|
ImGui::SetCursorPosX(5);
|
|
|
|
ImGui::InvisibleButton("##logo", ImVec2(menuBarHeight, menuBarHeight));
|
|
|
|
ImGui::OpenPopupOnItemClick("WindowingMenu", ImGuiPopupFlags_MouseButtonLeft);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::BeginPopup("WindowingMenu")) {
|
2023-12-19 13:10:25 +01:00
|
|
|
bool maximized = glfwGetWindowAttrib(m_window, GLFW_MAXIMIZED);
|
2023-08-19 19:12:15 +02:00
|
|
|
|
|
|
|
ImGui::BeginDisabled(!maximized);
|
2023-12-19 13:10:25 +01:00
|
|
|
if (ImGui::MenuItem(ICON_VS_CHROME_RESTORE " Restore")) glfwRestoreWindow(m_window);
|
2023-08-19 19:12:15 +02:00
|
|
|
ImGui::EndDisabled();
|
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
if (ImGui::MenuItem(ICON_VS_CHROME_MINIMIZE " Minimize")) glfwIconifyWindow(m_window);
|
2023-08-19 19:12:15 +02:00
|
|
|
|
|
|
|
ImGui::BeginDisabled(maximized);
|
2023-12-19 13:10:25 +01:00
|
|
|
if (ImGui::MenuItem(ICON_VS_CHROME_MAXIMIZE " Maximize")) glfwMaximizeWindow(m_window);
|
2023-08-19 19:12:15 +02:00
|
|
|
ImGui::EndDisabled();
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
|
|
|
if (ImGui::MenuItem(ICON_VS_CHROME_CLOSE " Close")) ImHexApi::System::closeImHex();
|
|
|
|
|
|
|
|
ImGui::EndPopup();
|
2022-02-15 22:36:36 +01:00
|
|
|
}
|
2021-08-18 22:36:46 +02:00
|
|
|
|
2023-11-14 00:03:22 +01:00
|
|
|
const static auto drawMenu = [] {
|
|
|
|
for (const auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMainMenuItems()) {
|
|
|
|
ImGui::GetStyle().TouchExtraPadding = scaled(ImVec2(0, 2));
|
2023-11-21 14:38:01 +01:00
|
|
|
if (ImGui::BeginMenu(Lang(menuItem.unlocalizedName))) {
|
2023-11-14 00:03:22 +01:00
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
ImGui::GetStyle().TouchExtraPadding = ImVec2(0, 0);
|
2020-11-28 22:01:50 +01:00
|
|
|
}
|
2020-11-11 09:22:55 +01:00
|
|
|
|
2023-11-14 00:03:22 +01:00
|
|
|
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
|
2024-01-08 21:51:48 +01:00
|
|
|
const auto &[unlocalizedNames, icon, shortcut, view, callback, enabledCallback] = menuItem;
|
|
|
|
|
|
|
|
createNestedMenu(unlocalizedNames, icon, *shortcut, callback, enabledCallback);
|
2023-11-14 00:03:22 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-01-08 23:41:28 +01:00
|
|
|
if (m_lastStartFrameTime > 0) {
|
|
|
|
static u32 menuEndPos = 0;
|
|
|
|
if (menuEndPos < m_searchBarPosition) {
|
2023-11-14 00:03:22 +01:00
|
|
|
drawMenu();
|
2024-01-08 23:41:28 +01:00
|
|
|
menuEndPos = ImGui::GetCursorPosX();
|
|
|
|
} else {
|
|
|
|
if (ImGui::BeginMenu(ICON_VS_MENU)) {
|
|
|
|
drawMenu();
|
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
2023-11-14 00:03:22 +01:00
|
|
|
}
|
2022-01-18 00:10:10 +01:00
|
|
|
}
|
2020-11-11 09:22:55 +01:00
|
|
|
|
2022-01-18 00:10:10 +01:00
|
|
|
this->drawTitleBar();
|
2020-11-10 15:26:38 +01:00
|
|
|
|
2022-01-18 00:10:10 +01:00
|
|
|
ImGui::EndMainMenuBar();
|
2021-08-21 00:52:11 +02:00
|
|
|
}
|
|
|
|
ImGui::PopStyleVar();
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Render toolbar
|
2021-08-21 00:52:11 +02:00
|
|
|
if (ImGui::BeginMenuBar()) {
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
for (const auto &callback : ContentRegistry::Interface::impl::getToolbarItems()) {
|
2021-08-21 00:52:11 +02:00
|
|
|
callback();
|
|
|
|
ImGui::SameLine();
|
|
|
|
}
|
|
|
|
|
2023-12-07 11:53:16 +01:00
|
|
|
if (auto provider = ImHexApi::Provider::get(); provider != nullptr) {
|
2023-12-21 16:56:12 +01:00
|
|
|
ImGui::BeginDisabled(TaskManager::getRunningTaskCount() > 0);
|
2023-12-07 11:53:16 +01:00
|
|
|
if (ImGui::CloseButton(ImGui::GetID("ProviderCloseButton"), ImGui::GetCursorScreenPos() + ImVec2(ImGui::GetContentRegionAvail().x - 17_scaled, 3_scaled))) {
|
|
|
|
ImHexApi::Provider::remove(provider);
|
|
|
|
}
|
2023-12-21 16:56:12 +01:00
|
|
|
ImGui::EndDisabled();
|
2023-12-07 11:53:16 +01:00
|
|
|
}
|
|
|
|
|
2021-08-21 00:52:11 +02:00
|
|
|
ImGui::EndMenuBar();
|
2020-11-23 23:57:19 +01:00
|
|
|
}
|
2020-11-11 14:41:44 +01:00
|
|
|
|
2024-01-08 21:51:48 +01:00
|
|
|
if (ImGui::BeginDragDropTargetCustom(ImGui::GetCurrentWindow()->MenuBarRect(), ImGui::GetCurrentWindow()->ID)) {
|
|
|
|
|
|
|
|
ImGui::EndDragDropTarget();
|
|
|
|
}
|
|
|
|
|
2021-12-10 16:09:55 +01:00
|
|
|
this->beginNativeWindowFrame();
|
2022-01-22 22:03:19 +01:00
|
|
|
|
2023-11-07 16:40:37 +01:00
|
|
|
if (ImHexApi::Provider::isValid() && isAnyViewOpen()) {
|
2023-11-08 11:53:26 +01:00
|
|
|
drawList->AddLine(
|
|
|
|
ImGui::GetWindowPos() + sidebarPos + ImVec2(sidebarWidth - 1_scaled, -2_scaled),
|
2023-12-07 23:47:25 +01:00
|
|
|
ImGui::GetWindowPos() + sidebarPos + ImGui::GetWindowSize() - ImVec2(dockSpaceSize.x + 1_scaled, footerHeight - ImGui::GetStyle().FramePadding.y - 1_scaled + menuBarHeight),
|
2023-11-08 11:53:26 +01:00
|
|
|
ImGui::GetColorU32(ImGuiCol_Separator));
|
2023-11-07 16:40:37 +01:00
|
|
|
}
|
2023-12-11 22:09:13 +01:00
|
|
|
} else {
|
|
|
|
ImGui::PopStyleVar();
|
2020-11-11 14:41:44 +01:00
|
|
|
}
|
2020-11-23 23:57:19 +01:00
|
|
|
ImGui::End();
|
2021-08-21 00:52:11 +02:00
|
|
|
ImGui::PopStyleVar(2);
|
2021-04-21 23:31:51 +02:00
|
|
|
|
2022-02-01 23:57:48 +01:00
|
|
|
// Plugin load error popups. These are not translated because they should always be readable, no matter if any localization could be loaded or not
|
|
|
|
{
|
2023-11-10 20:47:08 +01:00
|
|
|
auto drawPluginFolderTable = [] {
|
2023-11-16 22:24:06 +01:00
|
|
|
ImGuiExt::UnderlinedText("Plugin folders");
|
2023-07-22 22:59:05 +02:00
|
|
|
if (ImGui::BeginTable("plugins", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY | ImGuiTableFlags_SizingFixedFit, ImVec2(0, 100_scaled))) {
|
2022-02-01 23:57:48 +01:00
|
|
|
ImGui::TableSetupScrollFreeze(0, 1);
|
|
|
|
ImGui::TableSetupColumn("Path", ImGuiTableColumnFlags_WidthStretch, 0.2);
|
|
|
|
ImGui::TableSetupColumn("Exists", ImGuiTableColumnFlags_WidthFixed, ImGui::GetTextLineHeight() * 3);
|
|
|
|
|
|
|
|
ImGui::TableHeadersRow();
|
|
|
|
|
2022-03-04 11:36:37 +01:00
|
|
|
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Plugins, true)) {
|
2022-06-09 15:58:40 +02:00
|
|
|
const auto filePath = path / "builtin.hexplug";
|
2022-02-01 23:57:48 +01:00
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TableNextColumn();
|
2023-03-12 18:43:05 +01:00
|
|
|
ImGui::TextUnformatted(wolv::util::toUTF8String(filePath).c_str());
|
2022-02-01 23:57:48 +01:00
|
|
|
ImGui::TableNextColumn();
|
2023-12-23 21:09:41 +01:00
|
|
|
ImGui::TextUnformatted(wolv::io::fs::exists(filePath) ? "Yes" : "No");
|
2022-02-01 23:57:48 +01:00
|
|
|
}
|
|
|
|
ImGui::EndTable();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// No plugins error popup
|
2022-02-01 23:57:48 +01:00
|
|
|
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)!");
|
|
|
|
ImGui::TextUnformatted("Make sure you installed ImHex correctly.");
|
|
|
|
ImGui::TextUnformatted("There should be at least a 'builtin.hexplug' file in your plugins folder.");
|
|
|
|
|
|
|
|
ImGui::NewLine();
|
|
|
|
|
|
|
|
drawPluginFolderTable();
|
|
|
|
|
2023-07-22 22:59:05 +02:00
|
|
|
ImGui::NewLine();
|
|
|
|
if (ImGui::Button("Close ImHex", ImVec2(ImGui::GetContentRegionAvail().x, 0)))
|
|
|
|
ImHexApi::System::closeImHex(true);
|
|
|
|
|
2022-02-01 23:57:48 +01:00
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// No built-in plugin error popup
|
2022-02-01 23:57:48 +01:00
|
|
|
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
|
|
|
|
if (ImGui::BeginPopupModal("No Builtin Plugin", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove)) {
|
|
|
|
ImGui::TextUnformatted("The ImHex built-in plugins could not be loaded!");
|
|
|
|
ImGui::TextUnformatted("Make sure you installed ImHex correctly.");
|
|
|
|
ImGui::TextUnformatted("There should be at least a 'builtin.hexplug' file in your plugins folder.");
|
|
|
|
|
|
|
|
ImGui::NewLine();
|
|
|
|
|
|
|
|
drawPluginFolderTable();
|
|
|
|
|
2023-07-22 22:59:05 +02:00
|
|
|
ImGui::NewLine();
|
|
|
|
if (ImGui::Button("Close ImHex", ImVec2(ImGui::GetContentRegionAvail().x, 0)))
|
|
|
|
ImHexApi::System::closeImHex(true);
|
|
|
|
|
2022-02-01 23:57:48 +01:00
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Multiple built-in plugins error popup
|
2022-02-01 23:57:48 +01:00
|
|
|
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
|
|
|
|
if (ImGui::BeginPopupModal("Multiple Builtin Plugins", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove)) {
|
|
|
|
ImGui::TextUnformatted("ImHex found and attempted to load multiple built-in plugins!");
|
|
|
|
ImGui::TextUnformatted("Make sure you installed ImHex correctly and, if needed,");
|
|
|
|
ImGui::TextUnformatted("cleaned up older installations correctly,");
|
|
|
|
ImGui::TextUnformatted("There should be exactly one 'builtin.hexplug' file in any one your plugin folders.");
|
|
|
|
|
|
|
|
ImGui::NewLine();
|
|
|
|
|
|
|
|
drawPluginFolderTable();
|
|
|
|
|
2023-07-22 22:59:05 +02:00
|
|
|
ImGui::NewLine();
|
|
|
|
if (ImGui::Button("Close ImHex", ImVec2(ImGui::GetContentRegionAvail().x, 0)))
|
|
|
|
ImHexApi::System::closeImHex(true);
|
|
|
|
|
2022-02-01 23:57:48 +01:00
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
2021-04-21 23:31:51 +02:00
|
|
|
}
|
2023-02-17 12:03:53 +01:00
|
|
|
|
|
|
|
// Open popups when plugins requested it
|
2022-09-19 16:09:22 +02:00
|
|
|
{
|
2023-12-19 13:10:25 +01:00
|
|
|
std::scoped_lock lock(m_popupMutex);
|
|
|
|
m_popupsToOpen.remove_if([](const auto &name) {
|
2022-09-19 16:09:22 +02:00
|
|
|
if (ImGui::IsPopupOpen(name.c_str()))
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
ImGui::OpenPopup(name.c_str());
|
|
|
|
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
}
|
2022-01-18 00:10:10 +01:00
|
|
|
|
2023-04-07 10:21:27 +02:00
|
|
|
// Draw popup stack
|
|
|
|
{
|
2023-05-10 22:29:17 +02:00
|
|
|
static bool positionSet = false;
|
|
|
|
static bool sizeSet = false;
|
2023-07-23 18:22:53 +02:00
|
|
|
static double popupDelay = -2.0;
|
2024-01-06 17:38:55 +01:00
|
|
|
static u32 displayFrameCount = 0;
|
2023-05-10 22:29:17 +02:00
|
|
|
|
|
|
|
static std::unique_ptr<impl::PopupBase> currPopup;
|
2023-11-21 14:38:01 +01:00
|
|
|
static Lang name("");
|
2023-04-09 23:24:48 +02:00
|
|
|
|
2024-01-06 17:38:55 +01:00
|
|
|
AT_FIRST_TIME {
|
|
|
|
EventImHexClosing::subscribe([] {
|
|
|
|
currPopup.reset();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2023-05-10 22:29:17 +02:00
|
|
|
if (auto &popups = impl::PopupBase::getOpenPopups(); !popups.empty()) {
|
|
|
|
if (!ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId)) {
|
2023-07-23 18:22:53 +02:00
|
|
|
if (popupDelay <= -1.0) {
|
2023-12-11 11:42:33 +01:00
|
|
|
popupDelay = 0.2;
|
2023-07-23 18:22:53 +02:00
|
|
|
} else {
|
2023-12-19 13:10:25 +01:00
|
|
|
popupDelay -= m_lastFrameTime;
|
2023-12-11 11:42:33 +01:00
|
|
|
if (popupDelay < 0 || popups.size() == 1) {
|
2023-07-23 18:22:53 +02:00
|
|
|
popupDelay = -2.0;
|
|
|
|
currPopup = std::move(popups.back());
|
2023-11-21 14:38:01 +01:00
|
|
|
name = Lang(currPopup->getUnlocalizedName());
|
2024-01-06 17:38:55 +01:00
|
|
|
displayFrameCount = 0;
|
2023-07-23 18:22:53 +02:00
|
|
|
|
|
|
|
ImGui::OpenPopup(name);
|
|
|
|
popups.pop_back();
|
|
|
|
}
|
|
|
|
}
|
2023-05-10 22:29:17 +02:00
|
|
|
}
|
|
|
|
}
|
2023-04-07 10:21:27 +02:00
|
|
|
|
2023-05-10 22:29:17 +02:00
|
|
|
if (currPopup != nullptr) {
|
2023-04-07 10:21:27 +02:00
|
|
|
bool open = true;
|
|
|
|
|
2023-04-16 21:34:29 +02:00
|
|
|
const auto &minSize = currPopup->getMinSize();
|
|
|
|
const auto &maxSize = currPopup->getMaxSize();
|
|
|
|
const bool hasConstraints = minSize.x != 0 && minSize.y != 0 && maxSize.x != 0 && maxSize.y != 0;
|
2023-04-09 15:28:48 +02:00
|
|
|
|
2023-04-16 21:34:29 +02:00
|
|
|
if (hasConstraints)
|
|
|
|
ImGui::SetNextWindowSizeConstraints(minSize, maxSize);
|
|
|
|
else
|
|
|
|
ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiCond_Appearing);
|
2023-04-08 00:58:53 +02:00
|
|
|
|
2023-04-16 21:34:29 +02:00
|
|
|
auto* closeButton = currPopup->hasCloseButton() ? &open : nullptr;
|
2023-04-09 15:28:48 +02:00
|
|
|
|
2023-04-16 21:34:29 +02:00
|
|
|
const auto flags = currPopup->getFlags() | (!hasConstraints ? (ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize) : ImGuiWindowFlags_None);
|
2023-04-08 00:58:53 +02:00
|
|
|
|
2023-04-16 21:34:29 +02:00
|
|
|
if (!positionSet) {
|
2023-11-23 09:33:47 +01:00
|
|
|
ImGui::SetNextWindowPos(ImHexApi::System::getMainWindowPosition() + (ImHexApi::System::getMainWindowSize() / 2.0F), ImGuiCond_Always, ImVec2(0.5F, 0.5F));
|
2023-11-23 09:19:51 +01:00
|
|
|
|
2023-04-16 21:34:29 +02:00
|
|
|
if (sizeSet)
|
|
|
|
positionSet = true;
|
|
|
|
}
|
2023-04-09 15:28:48 +02:00
|
|
|
|
2023-04-16 21:34:29 +02:00
|
|
|
const auto createPopup = [&](bool displaying) {
|
|
|
|
if (displaying) {
|
2024-01-06 17:38:55 +01:00
|
|
|
displayFrameCount += 1;
|
2023-04-08 00:58:53 +02:00
|
|
|
currPopup->drawContent();
|
2023-04-16 21:34:29 +02:00
|
|
|
|
|
|
|
if (ImGui::GetWindowSize().x > ImGui::GetStyle().FramePadding.x * 10)
|
|
|
|
sizeSet = true;
|
2023-04-08 00:58:53 +02:00
|
|
|
|
2023-10-05 08:55:54 +02:00
|
|
|
// Reset popup position if it's outside the main window when multi-viewport is not enabled
|
|
|
|
// If not done, the popup will be stuck outside the main window and cannot be accessed anymore
|
|
|
|
if ((ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == ImGuiConfigFlags_None) {
|
|
|
|
const auto currWindowPos = ImGui::GetWindowPos();
|
|
|
|
const auto minWindowPos = ImHexApi::System::getMainWindowPosition() - ImGui::GetWindowSize();
|
|
|
|
const auto maxWindowPos = ImHexApi::System::getMainWindowPosition() + ImHexApi::System::getMainWindowSize();
|
|
|
|
if (currWindowPos.x > maxWindowPos.x || currWindowPos.y > maxWindowPos.y || currWindowPos.x < minWindowPos.x || currWindowPos.y < minWindowPos.y) {
|
|
|
|
positionSet = false;
|
|
|
|
GImGui->MovingWindow = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-08 00:58:53 +02:00
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
2023-04-16 21:34:29 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
if (currPopup->isModal())
|
|
|
|
createPopup(ImGui::BeginPopupModal(name, closeButton, flags));
|
|
|
|
else
|
|
|
|
createPopup(ImGui::BeginPopup(name, flags));
|
|
|
|
|
2024-01-06 17:38:55 +01:00
|
|
|
if (!ImGui::IsPopupOpen(name) && displayFrameCount < 10) {
|
|
|
|
ImGui::OpenPopup(name);
|
|
|
|
}
|
|
|
|
|
2023-12-26 00:22:47 +01:00
|
|
|
if (currPopup->shouldClose()) {
|
2023-04-16 21:34:29 +02:00
|
|
|
log::debug("Closing popup '{}'", name);
|
|
|
|
positionSet = sizeSet = false;
|
2023-04-07 10:21:27 +02:00
|
|
|
|
2023-05-10 22:29:17 +02:00
|
|
|
currPopup = nullptr;
|
2023-04-09 23:24:48 +02:00
|
|
|
}
|
2023-04-07 10:21:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-19 23:21:20 +01:00
|
|
|
// Draw Toasts
|
|
|
|
{
|
2023-12-26 00:22:47 +01:00
|
|
|
u32 index = 0;
|
|
|
|
for (const auto &toast : impl::ToastBase::getQueuedToasts() | std::views::take(4)) {
|
|
|
|
const auto toastHeight = 60_scaled;
|
2023-12-19 23:21:20 +01:00
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5_scaled);
|
2023-12-26 00:22:47 +01:00
|
|
|
ImGui::SetNextWindowSize(ImVec2(280_scaled, toastHeight));
|
|
|
|
ImGui::SetNextWindowPos((ImHexApi::System::getMainWindowPosition() + ImHexApi::System::getMainWindowSize()) - scaled({ 10, 10 }) - scaled({ 0, (10 + toastHeight) * index }), ImGuiCond_Always, ImVec2(1, 1));
|
|
|
|
if (ImGui::Begin(hex::format("##Toast_{}", index).c_str(), nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing)) {
|
2023-12-19 23:21:20 +01:00
|
|
|
auto drawList = ImGui::GetWindowDrawList();
|
|
|
|
|
|
|
|
const auto min = ImGui::GetWindowPos();
|
|
|
|
const auto max = min + ImGui::GetWindowSize();
|
|
|
|
|
|
|
|
drawList->PushClipRect(min, min + scaled({ 5, 60 }));
|
2023-12-26 00:22:47 +01:00
|
|
|
drawList->AddRectFilled(min, max, toast->getColor(), 5_scaled);
|
2023-12-19 23:21:20 +01:00
|
|
|
drawList->PopClipRect();
|
|
|
|
|
|
|
|
ImGui::Indent();
|
2023-12-26 00:22:47 +01:00
|
|
|
toast->draw();
|
2023-12-19 23:21:20 +01:00
|
|
|
ImGui::Unindent();
|
2023-12-26 00:22:47 +01:00
|
|
|
|
|
|
|
if (ImGui::IsWindowHovered() || toast->getAppearTime() <= 0)
|
|
|
|
toast->setAppearTime(ImGui::GetTime());
|
2023-12-19 23:21:20 +01:00
|
|
|
}
|
|
|
|
ImGui::End();
|
|
|
|
ImGui::PopStyleVar();
|
|
|
|
|
2023-12-26 00:22:47 +01:00
|
|
|
index += 1;
|
2023-12-19 23:21:20 +01:00
|
|
|
}
|
|
|
|
|
2023-12-26 00:22:47 +01:00
|
|
|
std::erase_if(impl::ToastBase::getQueuedToasts(), [](const auto &toast){
|
|
|
|
return toast->getAppearTime() > 0 && (toast->getAppearTime() + impl::ToastBase::VisibilityTime) < ImGui::GetTime();
|
|
|
|
});
|
2023-12-19 23:21:20 +01:00
|
|
|
}
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Run all deferred calls
|
2022-08-17 16:15:36 +02:00
|
|
|
TaskManager::runDeferredCalls();
|
|
|
|
|
2023-03-20 13:11:43 +01:00
|
|
|
// Draw main menu popups
|
2023-03-21 15:33:43 +01:00
|
|
|
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
|
2024-01-08 21:51:48 +01:00
|
|
|
const auto &[unlocalizedNames, icon, shortcut, view, callback, enabledCallback] = menuItem;
|
2023-03-20 13:11:43 +01:00
|
|
|
|
2023-12-19 12:22:28 +01:00
|
|
|
if (ImGui::BeginPopup(unlocalizedNames.front().get().c_str())) {
|
2024-01-08 21:51:48 +01:00
|
|
|
createNestedMenu({ unlocalizedNames.begin() + 1, unlocalizedNames.end() }, icon, *shortcut, callback, enabledCallback);
|
2023-03-20 13:11:43 +01:00
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-08 10:29:44 +01:00
|
|
|
EventFrameBegin::post();
|
2020-11-10 15:26:38 +01:00
|
|
|
}
|
|
|
|
|
2021-06-07 18:14:40 +02:00
|
|
|
void Window::frame() {
|
2022-07-30 22:01:49 +02:00
|
|
|
auto &io = ImGui::GetIO();
|
2023-02-17 12:03:53 +01:00
|
|
|
|
|
|
|
// Loop through all views and draw them
|
2023-03-21 15:33:43 +01:00
|
|
|
for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) {
|
2021-12-12 21:46:48 +01:00
|
|
|
ImGui::GetCurrentContext()->NextWindowData.ClearFlags();
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Draw always visible views
|
2023-11-21 13:47:50 +01:00
|
|
|
view->drawAlwaysVisibleContent();
|
2021-06-07 18:14:40 +02:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Skip views that shouldn't be processed currently
|
2021-06-07 18:14:40 +02:00
|
|
|
if (!view->shouldProcess())
|
|
|
|
continue;
|
|
|
|
|
2023-12-06 13:49:58 +01:00
|
|
|
const auto openViewCount = std::ranges::count_if(ContentRegistry::Views::impl::getEntries(), [](const auto &entry) {
|
2023-12-30 23:52:25 +01:00
|
|
|
const auto &[unlocalizedName, openView] = entry;
|
2023-12-06 13:49:58 +01:00
|
|
|
|
2023-12-30 23:52:25 +01:00
|
|
|
return openView->hasViewMenuItemEntry() && openView->shouldProcess();
|
2023-12-06 13:49:58 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
ImGuiWindowClass windowClass = {};
|
|
|
|
|
|
|
|
windowClass.DockNodeFlagsOverrideSet |= ImGuiDockNodeFlags_NoCloseButton;
|
|
|
|
|
|
|
|
if (openViewCount <= 1 || LayoutManager::isLayoutLocked())
|
|
|
|
windowClass.DockNodeFlagsOverrideSet |= ImGuiDockNodeFlags_NoTabBar;
|
|
|
|
|
|
|
|
ImGui::SetNextWindowClass(&windowClass);
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Draw view
|
2023-11-21 13:47:50 +01:00
|
|
|
view->draw();
|
2023-12-13 23:03:39 +01:00
|
|
|
view->trackViewOpenState();
|
2021-12-12 00:41:44 +01:00
|
|
|
|
2023-11-17 14:46:21 +01:00
|
|
|
if (view->getWindowOpenState()) {
|
2022-02-01 22:09:44 +01:00
|
|
|
auto window = ImGui::FindWindowByName(view->getName().c_str());
|
2022-01-11 20:29:06 +01:00
|
|
|
bool hasWindow = window != nullptr;
|
2022-02-01 22:09:44 +01:00
|
|
|
bool focused = false;
|
2021-12-23 15:11:38 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Get the currently focused view
|
2023-10-30 21:53:44 +01:00
|
|
|
if (hasWindow && (window->Flags & ImGuiWindowFlags_Popup) != ImGuiWindowFlags_Popup) {
|
|
|
|
auto windowName = View::toWindowName(name);
|
|
|
|
ImGui::Begin(windowName.c_str());
|
2021-12-31 11:01:22 +01:00
|
|
|
|
2023-10-30 21:53:44 +01:00
|
|
|
// Detect if the window is focused
|
2022-01-29 21:48:59 +01:00
|
|
|
focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy);
|
2023-10-30 21:53:44 +01:00
|
|
|
|
|
|
|
// Dock the window if it's not already docked
|
|
|
|
if (view->didWindowJustOpen() && !ImGui::IsWindowDocked()) {
|
|
|
|
ImGui::DockBuilderDockWindow(windowName.c_str(), ImHexApi::System::getMainDockSpaceId());
|
2023-12-13 23:03:39 +01:00
|
|
|
EventViewOpened::post(view.get());
|
2023-10-30 21:53:44 +01:00
|
|
|
}
|
|
|
|
|
2021-12-23 15:11:38 +01:00
|
|
|
ImGui::End();
|
|
|
|
}
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Pass on currently pressed keys to the shortcut handler
|
2023-12-19 13:10:25 +01:00
|
|
|
for (const auto &key : m_pressedKeys) {
|
2021-12-23 15:11:38 +01:00
|
|
|
ShortcutManager::process(view, io.KeyCtrl, io.KeyAlt, io.KeyShift, io.KeySuper, focused, key);
|
|
|
|
}
|
|
|
|
}
|
2021-06-07 18:14:40 +02:00
|
|
|
}
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Handle global shortcuts
|
2023-12-19 13:10:25 +01:00
|
|
|
for (const auto &key : m_pressedKeys) {
|
2023-11-17 14:46:21 +01:00
|
|
|
ShortcutManager::processGlobals(io.KeyCtrl, io.KeyAlt, io.KeyShift, io.KeySuper, key);
|
2022-07-30 22:01:49 +02:00
|
|
|
}
|
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
m_pressedKeys.clear();
|
2021-06-07 18:14:40 +02:00
|
|
|
}
|
|
|
|
|
2020-11-10 15:26:38 +01:00
|
|
|
void Window::frameEnd() {
|
2023-12-08 10:29:44 +01:00
|
|
|
EventFrameEnd::post();
|
2022-01-18 00:10:10 +01:00
|
|
|
|
2023-12-13 11:24:25 +01:00
|
|
|
TutorialManager::drawTutorial();
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Clean up all tasks that are done
|
2022-08-17 16:15:36 +02:00
|
|
|
TaskManager::collectGarbage();
|
|
|
|
|
2021-12-10 16:09:55 +01:00
|
|
|
this->endNativeWindowFrame();
|
2023-02-17 12:03:53 +01:00
|
|
|
|
2023-12-27 13:54:00 +01:00
|
|
|
// Finalize ImGui frame
|
2020-11-10 15:26:38 +01:00
|
|
|
ImGui::Render();
|
2020-11-17 13:58:50 +01:00
|
|
|
|
2023-12-27 13:54:00 +01:00
|
|
|
// Hash the draw data to determine if anything changed on the screen
|
|
|
|
// If not, there's no point in sending the draw data off to the GPU and swapping buffers
|
|
|
|
bool shouldRender = false;
|
|
|
|
{
|
|
|
|
u32 drawDataHash = 0;
|
|
|
|
static u32 previousDrawDataHash = 0;
|
|
|
|
|
|
|
|
for (const auto viewPort : ImGui::GetPlatformIO().Viewports) {
|
|
|
|
auto drawData = viewPort->DrawData;
|
|
|
|
for (int n = 0; n < drawData->CmdListsCount; n++) {
|
2023-12-27 16:33:49 +01:00
|
|
|
const ImDrawList *cmdList = drawData->CmdLists[n];
|
|
|
|
drawDataHash = ImHashData(cmdList->VtxBuffer.Data, cmdList->VtxBuffer.Size * sizeof(ImDrawVert), drawDataHash);
|
2023-12-27 13:54:00 +01:00
|
|
|
}
|
|
|
|
for (int n = 0; n < drawData->CmdListsCount; n++) {
|
2023-12-27 16:33:49 +01:00
|
|
|
const ImDrawList *cmdList = drawData->CmdLists[n];
|
|
|
|
drawDataHash = ImHashData(cmdList->IdxBuffer.Data, cmdList->IdxBuffer.Size * sizeof(ImDrawIdx), drawDataHash);
|
2023-12-27 13:54:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
shouldRender = drawDataHash != previousDrawDataHash;
|
|
|
|
previousDrawDataHash = drawDataHash;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shouldRender) {
|
|
|
|
int displayWidth, displayHeight;
|
|
|
|
glfwGetFramebufferSize(m_window, &displayWidth, &displayHeight);
|
|
|
|
glViewport(0, 0, displayWidth, displayHeight);
|
|
|
|
glClearColor(0.00F, 0.00F, 0.00F, 0.00F);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
2020-11-10 15:26:38 +01:00
|
|
|
|
2023-12-27 13:54:00 +01:00
|
|
|
glfwSwapBuffers(m_window);
|
|
|
|
|
|
|
|
m_unlockFrameRate = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLFWwindow *backupContext = glfwGetCurrentContext();
|
2020-11-23 15:51:40 +01:00
|
|
|
ImGui::UpdatePlatformWindows();
|
|
|
|
ImGui::RenderPlatformWindowsDefault();
|
2023-12-27 13:54:00 +01:00
|
|
|
glfwMakeContextCurrent(backupContext);
|
2023-05-11 18:44:50 +02:00
|
|
|
|
|
|
|
// Process layout load requests
|
|
|
|
// NOTE: This needs to be done before a new frame is started, otherwise ImGui won't handle docking correctly
|
2023-12-12 00:16:21 +01:00
|
|
|
LayoutManager::process();
|
|
|
|
WorkspaceManager::process();
|
2020-11-10 15:26:38 +01:00
|
|
|
}
|
|
|
|
|
2021-03-01 08:56:49 +01:00
|
|
|
void Window::initGLFW() {
|
2023-07-31 11:17:37 +02:00
|
|
|
bool restoreWindowPos = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.restore_window_pos", false);
|
|
|
|
|
2022-01-24 20:53:17 +01:00
|
|
|
glfwSetErrorCallback([](int error, const char *desc) {
|
2023-07-12 14:33:09 +02:00
|
|
|
if (error == GLFW_PLATFORM_ERROR) {
|
|
|
|
// Ignore error spam caused by Wayland not supporting moving or resizing
|
|
|
|
// windows or querying their position and size.
|
|
|
|
if (std::string_view(desc).contains("Wayland"))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-14 21:39:18 +02:00
|
|
|
try {
|
2023-07-12 14:33:09 +02:00
|
|
|
log::error("GLFW Error [0x{:05X}] : {}", error, desc);
|
2023-05-14 21:39:18 +02:00
|
|
|
} catch (const std::system_error &) {
|
|
|
|
// Catch and ignore system error that might be thrown when too many errors are being logged to a file
|
|
|
|
}
|
2020-11-11 14:41:44 +01:00
|
|
|
});
|
|
|
|
|
2022-01-13 14:34:27 +01:00
|
|
|
if (!glfwInit()) {
|
|
|
|
log::fatal("Failed to initialize GLFW!");
|
|
|
|
std::abort();
|
|
|
|
}
|
2020-11-10 15:26:38 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Set up used OpenGL version
|
2022-08-02 08:24:46 +02:00
|
|
|
#if defined(OS_MACOS)
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
|
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
2022-11-05 21:49:17 +01:00
|
|
|
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
|
impr: Don't force using discrete graphics card on macOS (#1341)
<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->
### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
When starting ImHex on a MacBook model with both integrated and discrete
graphics, it will force the computer to use the discrete graphics card.
This causes increased power usage, meaning the fans will spin up, the
battery will drain faster, etc. This program is not very graphics
intensive, so using the discrete graphics card shouldn't be needed.
### Implementation description
<!-- Explain what you did to correct the problem -->
I changed the
[`GLFW_COCOA_GRAPHICS_SWITCHING`](https://www.glfw.org/docs/latest/window_guide.html#window_hints_osx)
setting in GLFW to not enforce using the discrete graphics.
### Screenshots
<!-- If your change is visual, take a screenshot showing it. Ideally,
make before/after sceenshots -->
### Additional things
<!-- Anything else you would like to say -->
My editor is configured to automatically remove trailing whitespace, so
I hope that those whitespace changes are ok
2023-10-05 08:39:53 +02:00
|
|
|
glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, GLFW_TRUE);
|
2022-08-02 08:24:46 +02:00
|
|
|
#else
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
|
|
|
#endif
|
2020-11-10 15:26:38 +01:00
|
|
|
|
2022-02-15 23:07:48 +01:00
|
|
|
glfwWindowHint(GLFW_DECORATED, ImHexApi::System::isBorderlessWindowModeEnabled() ? GL_FALSE : GL_TRUE);
|
2021-04-21 20:06:48 +02:00
|
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
2023-05-22 12:00:35 +02:00
|
|
|
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
|
2021-11-28 11:57:52 +01:00
|
|
|
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
2023-10-04 12:00:32 +02:00
|
|
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
|
2020-11-30 00:03:12 +01:00
|
|
|
|
2023-07-31 11:17:37 +02:00
|
|
|
if (restoreWindowPos) {
|
|
|
|
int maximized = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.window.maximized", GLFW_FALSE);
|
|
|
|
glfwWindowHint(GLFW_MAXIMIZED, maximized);
|
|
|
|
}
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Create window
|
2023-12-19 13:10:25 +01:00
|
|
|
m_windowTitle = "ImHex";
|
|
|
|
m_window = glfwCreateWindow(1280_scaled, 720_scaled, m_windowTitle.c_str(), nullptr, nullptr);
|
2021-08-18 22:36:46 +02:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowUserPointer(m_window, this);
|
2020-11-23 23:57:19 +01:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
if (m_window == nullptr) {
|
2022-01-13 14:34:27 +01:00
|
|
|
log::fatal("Failed to create window!");
|
|
|
|
std::abort();
|
|
|
|
}
|
2020-11-10 15:26:38 +01:00
|
|
|
|
2023-10-30 16:40:14 +01:00
|
|
|
// Force window to be fully opaque by default
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowOpacity(m_window, 1.0F);
|
2023-10-30 16:40:14 +01:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwMakeContextCurrent(m_window);
|
2020-11-10 15:26:38 +01:00
|
|
|
glfwSwapInterval(1);
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Center window
|
2021-11-28 11:57:52 +01:00
|
|
|
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
|
|
|
|
if (monitor != nullptr) {
|
|
|
|
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
|
|
|
|
if (mode != nullptr) {
|
|
|
|
int monitorX, monitorY;
|
|
|
|
glfwGetMonitorPos(monitor, &monitorX, &monitorY);
|
|
|
|
|
|
|
|
int windowWidth, windowHeight;
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwGetWindowSize(m_window, &windowWidth, &windowHeight);
|
2021-11-28 11:57:52 +01:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowPos(m_window, monitorX + (mode->width - windowWidth) / 2, monitorY + (mode->height - windowHeight) / 2);
|
2021-11-28 11:57:52 +01:00
|
|
|
}
|
|
|
|
}
|
2021-11-28 01:17:48 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Set up initial window position
|
2021-08-18 22:36:46 +02:00
|
|
|
{
|
|
|
|
int x = 0, y = 0;
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwGetWindowPos(m_window, &x, &y);
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-07-31 11:17:37 +02:00
|
|
|
if (restoreWindowPos) {
|
|
|
|
x = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.window.x", x);
|
|
|
|
y = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.window.y", y);
|
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
ImHexApi::System::impl::setMainWindowPosition(x, y);
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowPos(m_window, x, y);
|
2021-08-18 22:36:46 +02:00
|
|
|
}
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Set up initial window size
|
2021-08-18 22:36:46 +02:00
|
|
|
{
|
|
|
|
int width = 0, height = 0;
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwGetWindowSize(m_window, &width, &height);
|
|
|
|
glfwSetWindowSize(m_window, width, height);
|
2023-07-31 11:17:37 +02:00
|
|
|
|
|
|
|
if (restoreWindowPos) {
|
|
|
|
width = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.window.width", width);
|
|
|
|
height = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.window.height", height);
|
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
ImHexApi::System::impl::setMainWindowSize(width, height);
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowSize(m_window, width, height);
|
2021-08-18 22:36:46 +02:00
|
|
|
}
|
2020-12-16 22:43:07 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Register window move callback
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowPosCallback(m_window, [](GLFWwindow *window, int x, int y) {
|
2022-02-01 18:09:40 +01:00
|
|
|
ImHexApi::System::impl::setMainWindowPosition(x, y);
|
2020-12-16 22:43:07 +01:00
|
|
|
|
2021-08-21 13:55:21 +02:00
|
|
|
if (auto g = ImGui::GetCurrentContext(); g == nullptr || g->WithinFrameScope) return;
|
2021-06-07 18:14:40 +02:00
|
|
|
|
2022-01-24 20:53:17 +01:00
|
|
|
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
|
2023-12-27 21:23:54 +01:00
|
|
|
win->m_unlockFrameRate = true;
|
|
|
|
|
2021-08-18 22:36:46 +02:00
|
|
|
win->frameBegin();
|
|
|
|
win->frame();
|
|
|
|
win->frameEnd();
|
|
|
|
});
|
2020-12-16 22:43:07 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Register window resize callback
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowSizeCallback(m_window, [](GLFWwindow *window, int width, int height) {
|
2022-07-06 10:21:38 +02:00
|
|
|
if (!glfwGetWindowAttrib(window, GLFW_ICONIFIED))
|
|
|
|
ImHexApi::System::impl::setMainWindowSize(width, height);
|
2021-06-07 18:14:40 +02:00
|
|
|
|
2021-08-21 13:55:21 +02:00
|
|
|
if (auto g = ImGui::GetCurrentContext(); g == nullptr || g->WithinFrameScope) return;
|
2021-08-18 22:36:46 +02:00
|
|
|
|
2022-01-24 20:53:17 +01:00
|
|
|
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
|
2023-12-27 21:23:54 +01:00
|
|
|
win->m_unlockFrameRate = true;
|
|
|
|
|
2021-06-07 18:14:40 +02:00
|
|
|
win->frameBegin();
|
|
|
|
win->frame();
|
|
|
|
win->frameEnd();
|
2023-02-16 08:53:23 +01:00
|
|
|
});
|
|
|
|
|
2023-12-27 21:23:54 +01:00
|
|
|
glfwSetCursorPosCallback(m_window, [](GLFWwindow *window, double, double) {
|
|
|
|
if (auto g = ImGui::GetCurrentContext(); g == nullptr || g->WithinFrameScope) return;
|
|
|
|
|
|
|
|
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
|
|
|
|
win->m_unlockFrameRate = true;
|
|
|
|
});
|
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
#if !defined(OS_WEB)
|
|
|
|
// Register key press callback
|
2023-12-29 11:29:31 +01:00
|
|
|
glfwSetInputMode(m_window, GLFW_LOCK_KEY_MODS, GLFW_TRUE);
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetKeyCallback(m_window, [](GLFWwindow *window, int key, int scanCode, int action, int mods) {
|
2023-10-04 12:00:32 +02:00
|
|
|
hex::unused(mods);
|
2022-08-03 23:32:34 +02:00
|
|
|
|
2023-06-02 14:43:45 +02:00
|
|
|
|
2023-11-18 15:18:33 +01:00
|
|
|
// 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);
|
|
|
|
|
|
|
|
// If the key name is only one character long, use the ASCII value instead
|
|
|
|
// Otherwise the keyboard was set to a non-English layout and the key name
|
|
|
|
// is not the same as the ASCII value
|
|
|
|
if (name.length() == 1) {
|
|
|
|
key = std::toupper(name[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
if (key == GLFW_KEY_UNKNOWN) return;
|
2023-05-23 13:20:18 +02:00
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
|
2023-11-17 14:46:21 +01:00
|
|
|
if (key != GLFW_KEY_LEFT_CONTROL && key != GLFW_KEY_RIGHT_CONTROL &&
|
|
|
|
key != GLFW_KEY_LEFT_ALT && key != GLFW_KEY_RIGHT_ALT &&
|
|
|
|
key != GLFW_KEY_LEFT_SHIFT && key != GLFW_KEY_RIGHT_SHIFT &&
|
|
|
|
key != GLFW_KEY_LEFT_SUPER && key != GLFW_KEY_RIGHT_SUPER
|
|
|
|
) {
|
2023-12-27 13:54:00 +01:00
|
|
|
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
|
2023-12-27 21:23:54 +01:00
|
|
|
win->m_unlockFrameRate = true;
|
2023-12-29 11:29:31 +01:00
|
|
|
|
|
|
|
if (!(mods & GLFW_MOD_NUM_LOCK)) {
|
|
|
|
if (key == GLFW_KEY_KP_0) key = GLFW_KEY_INSERT;
|
|
|
|
else if (key == GLFW_KEY_KP_1) key = GLFW_KEY_END;
|
|
|
|
else if (key == GLFW_KEY_KP_2) key = GLFW_KEY_DOWN;
|
|
|
|
else if (key == GLFW_KEY_KP_3) key = GLFW_KEY_PAGE_DOWN;
|
|
|
|
else if (key == GLFW_KEY_KP_4) key = GLFW_KEY_LEFT;
|
|
|
|
else if (key == GLFW_KEY_KP_6) key = GLFW_KEY_RIGHT;
|
|
|
|
else if (key == GLFW_KEY_KP_7) key = GLFW_KEY_HOME;
|
|
|
|
else if (key == GLFW_KEY_KP_8) key = GLFW_KEY_UP;
|
|
|
|
else if (key == GLFW_KEY_KP_9) key = GLFW_KEY_PAGE_UP;
|
|
|
|
}
|
|
|
|
|
2023-11-17 14:46:21 +01:00
|
|
|
win->m_pressedKeys.push_back(key);
|
|
|
|
}
|
2023-10-04 12:00:32 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
#endif
|
2020-11-11 14:41:44 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Register window close callback
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowCloseCallback(m_window, [](GLFWwindow *window) {
|
2023-12-08 10:29:44 +01:00
|
|
|
EventWindowClosing::post(window);
|
2023-02-17 12:03:53 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
// Register file drop callback
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetDropCallback(m_window, [](GLFWwindow *, int count, const char **paths) {
|
2023-02-17 12:03:53 +01:00
|
|
|
// Loop over all dropped files
|
2022-03-27 00:01:28 +01:00
|
|
|
for (int i = 0; i < count; i++) {
|
2022-03-16 13:23:36 +01:00
|
|
|
auto path = std::fs::path(reinterpret_cast<const char8_t *>(paths[i]));
|
2021-09-26 21:17:46 +02:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Check if a custom file handler can handle the file
|
2022-01-13 14:34:27 +01:00
|
|
|
bool handled = false;
|
2023-03-21 15:33:43 +01:00
|
|
|
for (const auto &[extensions, handler] : ContentRegistry::FileHandler::impl::getEntries()) {
|
2022-01-13 14:34:27 +01:00
|
|
|
for (const auto &extension : extensions) {
|
|
|
|
if (path.extension() == extension) {
|
2023-02-17 12:03:53 +01:00
|
|
|
// Pass the file to the handler and check if it was successful
|
|
|
|
if (!handler(path)) {
|
2022-02-01 18:09:40 +01:00
|
|
|
log::error("Handler for extensions '{}' failed to process file!", extension);
|
2023-02-17 12:03:53 +01:00
|
|
|
break;
|
|
|
|
}
|
2022-01-13 14:34:27 +01:00
|
|
|
|
|
|
|
handled = true;
|
2021-09-30 12:29:03 +02:00
|
|
|
}
|
2021-09-26 21:17:46 +02:00
|
|
|
}
|
|
|
|
}
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// If no custom handler was found, just open the file regularly
|
2022-01-13 14:34:27 +01:00
|
|
|
if (!handled)
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestOpenFile::post(path);
|
2021-09-26 21:17:46 +02:00
|
|
|
}
|
2020-11-17 13:58:50 +01:00
|
|
|
});
|
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowSizeLimits(m_window, 480_scaled, 360_scaled, GLFW_DONT_CARE, GLFW_DONT_CARE);
|
2021-11-28 11:57:52 +01:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwShowWindow(m_window);
|
2020-11-10 15:26:38 +01:00
|
|
|
}
|
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
void Window::resize(i32 width, i32 height) {
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwSetWindowSize(m_window, width, height);
|
2023-10-04 12:00:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-10 15:26:38 +01:00
|
|
|
void Window::initImGui() {
|
|
|
|
IMGUI_CHECKVERSION();
|
2021-02-03 00:56:33 +01:00
|
|
|
|
2023-11-29 23:47:37 +01:00
|
|
|
auto fonts = ImHexApi::Fonts::getFontAtlas();
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-12-20 16:31:31 +01:00
|
|
|
if (fonts == nullptr) {
|
|
|
|
fonts = IM_NEW(ImFontAtlas)();
|
|
|
|
|
|
|
|
fonts->AddFontDefault();
|
|
|
|
fonts->Build();
|
|
|
|
}
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Initialize ImGui and all other ImGui extensions
|
2022-02-01 22:09:44 +01:00
|
|
|
GImGui = ImGui::CreateContext(fonts);
|
|
|
|
GImPlot = ImPlot::CreateContext();
|
2021-08-17 13:39:46 +02:00
|
|
|
GImNodes = ImNodes::CreateContext();
|
2021-02-03 00:56:33 +01:00
|
|
|
|
2022-02-01 22:09:44 +01:00
|
|
|
ImGuiIO &io = ImGui::GetIO();
|
2022-01-24 20:53:17 +01:00
|
|
|
ImGuiStyle &style = ImGui::GetStyle();
|
2020-11-23 15:51:40 +01:00
|
|
|
|
2022-12-29 19:26:00 +01:00
|
|
|
ImNodes::GetStyle().Flags = ImNodesStyleFlags_NodeOutline | ImNodesStyleFlags_GridLines;
|
|
|
|
|
2021-02-18 17:10:56 +01:00
|
|
|
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard;
|
2022-11-07 00:04:47 +01:00
|
|
|
io.ConfigWindowsMoveFromTitleBarOnly = true;
|
2023-02-16 16:29:41 +01:00
|
|
|
io.FontGlobalScale = 1.0F;
|
2022-03-22 08:20:14 +01:00
|
|
|
|
2022-06-03 10:35:05 +02:00
|
|
|
if (glfwGetPrimaryMonitor() != nullptr) {
|
2023-10-21 23:07:33 +02:00
|
|
|
bool multiWindowEnabled = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.multi_windows", false);
|
2023-04-10 22:51:21 +02:00
|
|
|
|
|
|
|
if (multiWindowEnabled)
|
2022-03-22 08:20:14 +01:00
|
|
|
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
|
|
|
}
|
2021-02-18 17:10:56 +01:00
|
|
|
|
2022-01-11 16:02:05 +01:00
|
|
|
io.ConfigViewportsNoTaskBarIcon = false;
|
2020-11-23 15:51:40 +01:00
|
|
|
|
2021-08-17 13:39:46 +02:00
|
|
|
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
|
|
|
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkCreationOnSnap);
|
|
|
|
|
2023-02-17 12:03:53 +01:00
|
|
|
// Allow ImNodes links to always be detached without holding down any button
|
2021-08-17 13:39:46 +02:00
|
|
|
{
|
2023-02-17 12:03:53 +01:00
|
|
|
static bool always = true;
|
2021-08-17 13:39:46 +02:00
|
|
|
ImNodes::GetIO().LinkDetachWithModifierClick.Modifier = &always;
|
|
|
|
}
|
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
io.UserData = &m_imguiCustomData;
|
2021-02-25 00:17:41 +01:00
|
|
|
|
2022-07-29 17:37:30 +02:00
|
|
|
auto scale = ImHexApi::System::getGlobalScale();
|
|
|
|
style.ScaleAllSizes(scale);
|
|
|
|
io.DisplayFramebufferScale = ImVec2(scale, scale);
|
2023-02-17 12:03:00 +01:00
|
|
|
io.Fonts->SetTexID(fonts->TexID);
|
2020-12-11 14:24:42 +01:00
|
|
|
|
2020-11-23 15:51:40 +01:00
|
|
|
style.WindowMenuButtonPosition = ImGuiDir_None;
|
2022-02-01 22:09:44 +01:00
|
|
|
style.IndentSpacing = 10.0F;
|
2023-03-17 19:58:08 +01:00
|
|
|
style.DisplaySafeAreaPadding = ImVec2(0.0F, 0.0F);
|
2020-11-10 15:26:38 +01:00
|
|
|
|
2020-11-15 15:49:21 +01:00
|
|
|
// Install custom settings handler
|
2023-02-17 12:03:53 +01:00
|
|
|
{
|
|
|
|
ImGuiSettingsHandler handler;
|
|
|
|
handler.TypeName = "ImHex";
|
|
|
|
handler.TypeHash = ImHashStr("ImHex");
|
|
|
|
|
|
|
|
handler.ReadOpenFn = [](ImGuiContext *ctx, ImGuiSettingsHandler *, const char *) -> void* { return ctx; };
|
|
|
|
|
2023-12-02 14:35:44 +01:00
|
|
|
handler.ReadLineFn = [](ImGuiContext *, ImGuiSettingsHandler *handler, void *, const char *line) {
|
2023-12-27 16:33:49 +01:00
|
|
|
auto window = static_cast<Window*>(handler->UserData);
|
2023-12-02 14:35:44 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) {
|
2023-12-19 12:22:28 +01:00
|
|
|
std::string format = view->getUnlocalizedName().get() + "=%d";
|
2023-02-17 12:03:53 +01:00
|
|
|
sscanf(line, format.c_str(), &view->getWindowOpenState());
|
|
|
|
}
|
2023-03-21 15:33:43 +01:00
|
|
|
for (auto &[name, function, detached] : ContentRegistry::Tools::impl::getEntries()) {
|
2023-02-17 12:03:53 +01:00
|
|
|
std::string format = name + "=%d";
|
|
|
|
sscanf(line, format.c_str(), &detached);
|
|
|
|
}
|
2023-12-02 14:35:44 +01:00
|
|
|
|
|
|
|
int width = 0, height = 0;
|
|
|
|
sscanf(line, "MainWindowSize=%d,%d", &width, &height);
|
|
|
|
|
|
|
|
if (width > 0 && height > 0) {
|
|
|
|
TaskManager::doLater([width, height, window]{
|
|
|
|
glfwSetWindowSize(window->m_window, width, height);
|
|
|
|
});
|
|
|
|
}
|
2023-02-17 12:03:53 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
handler.WriteAllFn = [](ImGuiContext *, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buf) {
|
|
|
|
buf->appendf("[%s][General]\n", handler->TypeName);
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) {
|
2023-02-17 12:03:53 +01:00
|
|
|
buf->appendf("%s=%d\n", name.c_str(), view->getWindowOpenState());
|
|
|
|
}
|
2023-03-21 15:33:43 +01:00
|
|
|
for (auto &[name, function, detached] : ContentRegistry::Tools::impl::getEntries()) {
|
2023-02-17 12:03:53 +01:00
|
|
|
buf->appendf("%s=%d\n", name.c_str(), detached);
|
|
|
|
}
|
|
|
|
|
|
|
|
buf->append("\n");
|
|
|
|
};
|
|
|
|
|
|
|
|
handler.UserData = this;
|
2023-12-13 11:24:25 +01:00
|
|
|
|
|
|
|
auto context = ImGui::GetCurrentContext();
|
|
|
|
context->SettingsHandlers.push_back(handler);
|
|
|
|
context->TestEngineHookItems = true;
|
2023-02-17 12:03:53 +01:00
|
|
|
|
2023-07-07 09:20:33 +02:00
|
|
|
io.IniFilename = nullptr;
|
2023-02-17 12:03:53 +01:00
|
|
|
}
|
2021-03-01 08:56:49 +01:00
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
ImGui_ImplGlfw_InitForOpenGL(m_window, true);
|
2021-04-21 20:06:48 +02:00
|
|
|
|
2022-08-02 13:12:12 +02:00
|
|
|
#if defined(OS_MACOS)
|
|
|
|
ImGui_ImplOpenGL3_Init("#version 150");
|
2023-10-04 12:00:32 +02:00
|
|
|
#elif defined(OS_WEB)
|
|
|
|
ImGui_ImplOpenGL3_Init();
|
2022-08-02 13:12:12 +02:00
|
|
|
#else
|
|
|
|
ImGui_ImplOpenGL3_Init("#version 130");
|
|
|
|
#endif
|
2021-08-21 00:52:11 +02:00
|
|
|
|
|
|
|
for (const auto &plugin : PluginManager::getPlugins())
|
|
|
|
plugin.setImGuiContext(ImGui::GetCurrentContext());
|
2023-02-16 18:06:40 +01:00
|
|
|
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestInitThemeHandlers::post();
|
2020-11-10 15:26:38 +01:00
|
|
|
}
|
|
|
|
|
2022-01-18 00:10:10 +01:00
|
|
|
void Window::exitGLFW() {
|
2023-07-31 11:17:37 +02:00
|
|
|
{
|
|
|
|
int x = 0, y = 0, width = 0, height = 0, maximized = 0;
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwGetWindowPos(m_window, &x, &y);
|
|
|
|
glfwGetWindowSize(m_window, &width, &height);
|
|
|
|
maximized = glfwGetWindowAttrib(m_window, GLFW_MAXIMIZED);
|
2023-07-31 11:17:37 +02:00
|
|
|
|
2023-11-22 12:47:28 +01:00
|
|
|
ContentRegistry::Settings::write("hex.builtin.setting.interface", "hex.builtin.setting.interface.window.x", x);
|
2023-07-31 11:17:37 +02:00
|
|
|
ContentRegistry::Settings::write("hex.builtin.setting.interface", "hex.builtin.setting.interface.window.y", y);
|
|
|
|
ContentRegistry::Settings::write("hex.builtin.setting.interface", "hex.builtin.setting.interface.window.width", width);
|
|
|
|
ContentRegistry::Settings::write("hex.builtin.setting.interface", "hex.builtin.setting.interface.window.height", height);
|
|
|
|
ContentRegistry::Settings::write("hex.builtin.setting.interface", "hex.builtin.setting.interface.window.maximized", maximized);
|
|
|
|
}
|
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
glfwDestroyWindow(m_window);
|
2020-11-10 15:26:38 +01:00
|
|
|
glfwTerminate();
|
2023-05-15 11:30:24 +02:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
m_window = nullptr;
|
2020-11-10 15:26:38 +01:00
|
|
|
}
|
|
|
|
|
2022-01-18 00:10:10 +01:00
|
|
|
void Window::exitImGui() {
|
2020-11-10 15:26:38 +01:00
|
|
|
ImGui_ImplOpenGL3_Shutdown();
|
|
|
|
ImGui_ImplGlfw_Shutdown();
|
2021-03-02 13:48:23 +01:00
|
|
|
ImPlot::DestroyContext();
|
2020-11-10 15:26:38 +01:00
|
|
|
ImGui::DestroyContext();
|
|
|
|
}
|
|
|
|
|
2021-06-18 20:09:36 +02:00
|
|
|
}
|