1 #include "window.hpp" 2 3 #include <hex.hpp> 4 #include <hex/api/content_registry.hpp> 5 6 #include <iostream> 7 #include <numeric> 8 #include <typeinfo> 9 10 #include <imgui.h> 11 #include <imgui_internal.h> 12 #include <imgui_impl_glfw.h> 13 #include <imgui_impl_opengl3.h> 14 #include <imgui_freetype.h> 15 #include <imgui_imhex_extensions.h> 16 17 #include "helpers/plugin_handler.hpp" 18 19 #include <glad/glad.h> 20 #include <GLFW/glfw3.h> 21 22 namespace hex { 23 ImHexSettingsHandler_ReadOpenFn(ImGuiContext * ctx,ImGuiSettingsHandler *,const char *)24 void *ImHexSettingsHandler_ReadOpenFn(ImGuiContext *ctx, ImGuiSettingsHandler *, const char *) { 25 return ctx; // Unused, but the return value has to be non-null 26 } 27 ImHexSettingsHandler_ReadLine(ImGuiContext *,ImGuiSettingsHandler * handler,void *,const char * line)28 void ImHexSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler *handler, void *, const char* line) { 29 for (auto &view : ContentRegistry::Views::getEntries()) { 30 std::string format = std::string(view->getName()) + "=%d"; 31 sscanf(line, format.c_str(), &view->getWindowOpenState()); 32 } 33 } 34 ImHexSettingsHandler_WriteAll(ImGuiContext * ctx,ImGuiSettingsHandler * handler,ImGuiTextBuffer * buf)35 void ImHexSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buf) { 36 buf->reserve(buf->size() + 0x20); // Ballpark reserve 37 38 buf->appendf("[%s][General]\n", handler->TypeName); 39 40 for (auto &view : ContentRegistry::Views::getEntries()) { 41 buf->appendf("%s=%d\n", typeid(*view).name(), view->getWindowOpenState()); 42 } 43 44 buf->append("\n"); 45 } 46 Window(int & argc,char ** & argv)47 Window::Window(int &argc, char **&argv) { 48 hex::SharedData::mainArgc = argc; 49 hex::SharedData::mainArgv = argv; 50 51 this->initGLFW(); 52 this->initImGui(); 53 54 EventManager::subscribe(Events::SettingsChanged, this, [](auto) -> std::any { 55 { 56 auto theme = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color"); 57 58 if (theme.has_value()) { 59 switch (static_cast<int>(theme.value())) { 60 default: 61 case 0: /* Dark theme */ 62 ImGui::StyleColorsDark(); 63 break; 64 case 1: /* Light theme */ 65 ImGui::StyleColorsLight(); 66 break; 67 case 2: /* Classic theme */ 68 ImGui::StyleColorsClassic(); 69 break; 70 } 71 ImGui::GetStyle().Colors[ImGuiCol_DockingEmptyBg] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg]; 72 } 73 } 74 75 { 76 auto language = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.language"); 77 78 if (language.has_value()) 79 LangEntry::loadLanguage(static_cast<std::string>(language.value())); 80 } 81 82 return { }; 83 }); 84 85 EventManager::subscribe(Events::FileLoaded, this, [this](auto userData) -> std::any { 86 auto path = std::any_cast<std::string>(userData); 87 88 this->m_recentFiles.push_front(path); 89 90 { 91 std::list<std::string> uniques; 92 for (auto &file : this->m_recentFiles) { 93 94 bool exists = false; 95 for (auto &unique : uniques) { 96 if (file == unique) 97 exists = true; 98 } 99 100 if (!exists) 101 uniques.push_back(file); 102 103 if (uniques.size() > 5) 104 break; 105 } 106 this->m_recentFiles = uniques; 107 } 108 109 { 110 std::vector<std::string> recentFilesVector; 111 std::copy(this->m_recentFiles.begin(), this->m_recentFiles.end(), std::back_inserter(recentFilesVector)); 112 113 ContentRegistry::Settings::write("hex.builtin.setting.imhex", "hex.builtin.setting.imhex.recent_files", recentFilesVector); 114 } 115 116 return { }; 117 }); 118 119 EventManager::subscribe(Events::CloseImHex, this, [this](auto) -> std::any { 120 glfwSetWindowShouldClose(this->m_window, true); 121 122 return { }; 123 }); 124 125 this->initPlugins(); 126 127 ContentRegistry::Settings::load(); 128 View::postEvent(Events::SettingsChanged); 129 130 for (const auto &path : ContentRegistry::Settings::read("hex.builtin.setting.imhex", "hex.builtin.setting.imhex.recent_files")) 131 this->m_recentFiles.push_back(path); 132 } 133 ~Window()134 Window::~Window() { 135 this->deinitImGui(); 136 this->deinitGLFW(); 137 ContentRegistry::Settings::store(); 138 139 this->deinitPlugins(); 140 141 EventManager::unsubscribe(Events::SettingsChanged, this); 142 EventManager::unsubscribe(Events::FileLoaded, this); 143 EventManager::unsubscribe(Events::CloseImHex, this); 144 } 145 loop()146 void Window::loop() { 147 while (!glfwWindowShouldClose(this->m_window)) { 148 this->frameBegin(); 149 150 for (const auto &call : View::getDeferedCalls()) 151 call(); 152 View::getDeferedCalls().clear(); 153 154 for (auto &view : ContentRegistry::Views::getEntries()) { 155 view->drawAlwaysVisible(); 156 157 if (!view->shouldProcess()) 158 continue; 159 160 auto minSize = view->getMinSize(); 161 minSize.x *= this->m_globalScale; 162 minSize.y *= this->m_globalScale; 163 164 ImGui::SetNextWindowSizeConstraints(minSize, view->getMaxSize()); 165 view->drawContent(); 166 } 167 168 View::drawCommonInterfaces(); 169 170 #ifdef DEBUG 171 if (this->m_demoWindowOpen) 172 ImGui::ShowDemoWindow(&this->m_demoWindowOpen); 173 #endif 174 175 this->frameEnd(); 176 } 177 } 178 setFont(const std::filesystem::path & path)179 bool Window::setFont(const std::filesystem::path &path) { 180 if (!std::filesystem::exists(path)) 181 return false; 182 183 auto &io = ImGui::GetIO(); 184 185 // If we have a custom font, then rescaling is unnecessary and will make it blurry 186 io.FontGlobalScale = 1.0f; 187 188 // Load font data & build atlas 189 std::uint8_t *px; 190 int w, h; 191 192 ImVector<ImWchar> ranges; 193 ImFontGlyphRangesBuilder glyphRangesBuilder; 194 glyphRangesBuilder.AddRanges(io.Fonts->GetGlyphRangesDefault()); 195 glyphRangesBuilder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); 196 glyphRangesBuilder.AddRanges(io.Fonts->GetGlyphRangesChineseFull()); 197 glyphRangesBuilder.AddRanges(io.Fonts->GetGlyphRangesCyrillic()); 198 glyphRangesBuilder.AddRanges(io.Fonts->GetGlyphRangesKorean()); 199 glyphRangesBuilder.AddRanges(io.Fonts->GetGlyphRangesThai()); 200 glyphRangesBuilder.AddRanges(io.Fonts->GetGlyphRangesVietnamese()); 201 glyphRangesBuilder.BuildRanges(&ranges); 202 203 io.Fonts->AddFontFromFileTTF(path.string().c_str(), std::floor(14.0f * this->m_fontScale), nullptr, ranges.Data); // Needs conversion to char for Windows 204 ImGuiFreeType::BuildFontAtlas(io.Fonts, ImGuiFreeType::Monochrome); 205 io.Fonts->GetTexDataAsRGBA32(&px, &w, &h); 206 207 // Create new font atlas 208 GLuint tex; 209 glGenTextures(1, &tex); 210 glBindTexture(GL_TEXTURE_2D, tex); 211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 212 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 213 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA8, GL_UNSIGNED_INT, px); 214 io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(tex)); 215 216 return true; 217 } 218 frameBegin()219 void Window::frameBegin() { 220 glfwPollEvents(); 221 222 ImGui_ImplOpenGL3_NewFrame(); 223 ImGui_ImplGlfw_NewFrame(); 224 ImGui::NewFrame(); 225 226 ImGuiViewport* viewport = ImGui::GetMainViewport(); 227 ImGui::SetNextWindowPos(viewport->GetWorkPos()); 228 ImGui::SetNextWindowSize(viewport->GetWorkSize()); 229 ImGui::SetNextWindowViewport(viewport->ID); 230 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); 231 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); 232 233 ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking 234 | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse 235 | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize 236 | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoBringToFrontOnFocus 237 | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; 238 239 ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; 240 241 if (ImGui::Begin("DockSpace", nullptr, windowFlags)) { 242 ImGui::PopStyleVar(2); 243 244 ImGui::DockSpace(ImGui::GetID("MainDock"), ImVec2(0.0f, ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeightWithSpacing() - 1)); 245 246 ImGui::Separator(); 247 for (const auto &callback : ContentRegistry::Interface::getFooterItems()) { 248 auto prevIdx = ImGui::GetWindowDrawList()->_VtxCurrentIdx; 249 callback(); 250 auto currIdx = ImGui::GetWindowDrawList()->_VtxCurrentIdx; 251 252 // Only draw separator if something was actually drawn 253 if (prevIdx != currIdx) { 254 ImGui::SameLine(); 255 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); 256 ImGui::SameLine(); 257 } 258 } 259 260 if (ImGui::BeginMenuBar()) { 261 262 for (const auto& menu : { "hex.menu.file"_lang, "hex.menu.edit"_lang, "hex.menu.view"_lang, "hex.menu.help"_lang }) 263 if (ImGui::BeginMenu(menu)) ImGui::EndMenu(); 264 265 if (ImGui::BeginMenu("hex.menu.view"_lang)) { 266 for (auto &view : ContentRegistry::Views::getEntries()) { 267 if (view->hasViewMenuItemEntry()) 268 ImGui::MenuItem((std::string(view->getName()) + " " + "hex.menu.view"_lang).c_str(), "", &view->getWindowOpenState()); 269 } 270 ImGui::EndMenu(); 271 } 272 273 for (auto &view : ContentRegistry::Views::getEntries()) { 274 view->drawMenu(); 275 } 276 277 if (ImGui::BeginMenu("hex.menu.view"_lang)) { 278 ImGui::Separator(); 279 ImGui::MenuItem("hex.menu.view.fps"_lang, "", &this->m_fpsVisible); 280 #ifdef DEBUG 281 ImGui::MenuItem("hex.menu.view.demo"_lang, "", &this->m_demoWindowOpen); 282 #endif 283 ImGui::EndMenu(); 284 } 285 286 if (this->m_fpsVisible) { 287 char buffer[0x20]; 288 snprintf(buffer, 0x20, "%.1f FPS", ImGui::GetIO().Framerate); 289 290 ImGui::SameLine(ImGui::GetWindowWidth() - ImGui::GetFontSize() * strlen(buffer) + 20); 291 ImGui::TextUnformatted(buffer); 292 } 293 294 ImGui::EndMenuBar(); 295 } 296 297 if (auto &[key, mods] = Window::s_currShortcut; key != -1) { 298 for (auto &view : ContentRegistry::Views::getEntries()) { 299 if (view->shouldProcess()) { 300 if (view->handleShortcut(key, mods)) 301 break; 302 } 303 } 304 305 Window::s_currShortcut = { -1, -1 }; 306 } 307 308 bool anyViewOpen = false; 309 for (auto &view : ContentRegistry::Views::getEntries()) 310 anyViewOpen = anyViewOpen || (view->getWindowOpenState() && view->isAvailable()); 311 312 if (!anyViewOpen && SharedData::currentProvider == nullptr) { 313 char title[256]; 314 ImFormatString(title, IM_ARRAYSIZE(title), "%s/DockSpace_%08X", ImGui::GetCurrentWindow()->Name, ImGui::GetID("MainDock")); 315 if (ImGui::Begin(title)) { 316 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10 * this->m_globalScale, 10 * this->m_globalScale)); 317 if (ImGui::BeginChild("Welcome Screen", ImVec2(0, 0), false, ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoDecoration)) { 318 this->drawWelcomeScreen(); 319 } 320 ImGui::EndChild(); 321 ImGui::PopStyleVar(); 322 } 323 ImGui::End(); 324 } 325 326 } 327 ImGui::End(); 328 } 329 frameEnd()330 void Window::frameEnd() { 331 ImGui::Render(); 332 333 int displayWidth, displayHeight; 334 glfwGetFramebufferSize(this->m_window, &displayWidth, &displayHeight); 335 glViewport(0, 0, displayWidth, displayHeight); 336 glClearColor(0.45f, 0.55f, 0.60f, 1.00f); 337 glClear(GL_COLOR_BUFFER_BIT); 338 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 339 340 GLFWwindow* backup_current_context = glfwGetCurrentContext(); 341 ImGui::UpdatePlatformWindows(); 342 ImGui::RenderPlatformWindowsDefault(); 343 glfwMakeContextCurrent(backup_current_context); 344 345 glfwSwapBuffers(this->m_window); 346 } 347 drawWelcomeScreen()348 void Window::drawWelcomeScreen() { 349 ImGui::UnderlinedText("hex.welcome.header.main"_lang, ImGui::GetStyleColorVec4(ImGuiCol_Text)); 350 351 ImGui::NewLine(); 352 353 const auto availableSpace = ImGui::GetContentRegionAvail(); 354 const auto rowHeight = ImGui::GetTextLineHeightWithSpacing() * 6; 355 356 ImGui::Indent(); 357 if (ImGui::BeginTable("Welcome Left", 1, ImGuiTableFlags_NoBordersInBody, ImVec2(availableSpace.x / 2, availableSpace.y))) { 358 ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight); 359 ImGui::TableNextColumn(); 360 ImGui::TextUnformatted("hex.welcome.header.start"_lang); 361 { 362 if (ImGui::BulletHyperlink("hex.welcome.start.open_file"_lang)) 363 EventManager::post(Events::OpenWindow, "Open File"); 364 if (ImGui::BulletHyperlink("hex.welcome.start.open_project"_lang)) 365 EventManager::post(Events::OpenWindow, "Open Project"); 366 } 367 ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight); 368 ImGui::TableNextColumn(); 369 ImGui::TextUnformatted("hex.welcome.start.recent"_lang); 370 { 371 if (!this->m_recentFiles.empty()) { 372 for (auto &path : this->m_recentFiles) { 373 if (ImGui::BulletHyperlink(std::filesystem::path(path).filename().string().c_str())) { 374 EventManager::post(Events::FileDropped, path.c_str()); 375 break; 376 } 377 } 378 } 379 } 380 ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight); 381 ImGui::TableNextColumn(); 382 ImGui::TextUnformatted("hex.welcome.header.help"_lang); 383 { 384 if (ImGui::BulletHyperlink("hex.welcome.help.repo"_lang)) hex::openWebpage("hex.welcome.help.repo.link"_lang); 385 if (ImGui::BulletHyperlink("hex.welcome.help.gethelp"_lang)) hex::openWebpage("hex.welcome.help.gethelp.link"_lang); 386 } 387 388 ImGui::EndTable(); 389 } 390 ImGui::SameLine(); 391 if (ImGui::BeginTable("Welcome Right", 1, ImGuiTableFlags_NoBordersInBody, ImVec2(availableSpace.x / 2, availableSpace.y))) { 392 ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight); 393 ImGui::TableNextColumn(); 394 ImGui::TextUnformatted("hex.welcome.header.customize"_lang); 395 { 396 if (ImGui::DescriptionButton("hex.welcome.customize.settings.title"_lang, "hex.welcome.customize.settings.desc"_lang, ImVec2(ImGui::GetContentRegionAvail().x * 0.8F, 0))) 397 EventManager::post(Events::OpenWindow, "hex.view.settings.title"); 398 } 399 ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight); 400 ImGui::TableNextColumn(); 401 ImGui::TextUnformatted("hex.welcome.header.learn"_lang); 402 { 403 if (ImGui::DescriptionButton("hex.welcome.learn.latest.title"_lang, "hex.welcome.learn.latest.desc"_lang, ImVec2(ImGui::GetContentRegionAvail().x * 0.8F, 0))) 404 hex::openWebpage("hex.welcome.learn.latest.link"_lang); 405 if (ImGui::DescriptionButton("hex.welcome.learn.pattern.title"_lang, "hex.welcome.learn.pattern.desc"_lang, ImVec2(ImGui::GetContentRegionAvail().x * 0.8F, 0))) 406 hex::openWebpage("hex.welcome.learn.pattern.link"_lang); 407 if (ImGui::DescriptionButton("hex.welcome.learn.plugins.title"_lang, "hex.welcome.learn.plugins.desc"_lang, ImVec2(ImGui::GetContentRegionAvail().x * 0.8F, 0))) 408 hex::openWebpage("hex.welcome.learn.plugins.link"_lang); 409 } 410 411 auto extraWelcomeScreenEntries = ContentRegistry::Interface::getWelcomeScreenEntries(); 412 if (!extraWelcomeScreenEntries.empty()) { 413 ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight); 414 ImGui::TableNextColumn(); 415 ImGui::TextUnformatted("hex.welcome.header.various"_lang); 416 { 417 for (const auto &callback : extraWelcomeScreenEntries) 418 callback(); 419 } 420 } 421 422 423 ImGui::EndTable(); 424 } 425 } 426 initGLFW()427 void Window::initGLFW() { 428 glfwSetErrorCallback([](int error, const char* desc) { 429 fprintf(stderr, "Glfw Error %d: %s\n", error, desc); 430 }); 431 432 if (!glfwInit()) 433 throw std::runtime_error("Failed to initialize GLFW!"); 434 435 #ifdef __APPLE__ 436 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 437 #endif 438 439 if (auto *monitor = glfwGetPrimaryMonitor(); monitor) { 440 float xscale, yscale; 441 glfwGetMonitorContentScale(monitor, &xscale, &yscale); 442 443 // In case the horizontal and vertical scale are different, fall back on the average 444 this->m_globalScale = this->m_fontScale = std::midpoint(xscale, yscale); 445 } 446 447 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 448 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); 449 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 450 451 452 this->m_window = glfwCreateWindow(1280 * this->m_globalScale, 720 * this->m_globalScale, "ImHex", nullptr, nullptr); 453 454 455 if (this->m_window == nullptr) 456 throw std::runtime_error("Failed to create window!"); 457 458 glfwMakeContextCurrent(this->m_window); 459 glfwSwapInterval(1); 460 461 { 462 int x = 0, y = 0; 463 glfwGetWindowPos(this->m_window, &x, &y); 464 SharedData::windowPos = ImVec2(x, y); 465 } 466 467 { 468 int width = 0, height = 0; 469 glfwGetWindowSize(this->m_window, &width, &height); 470 SharedData::windowSize = ImVec2(width, height); 471 } 472 473 glfwSetWindowPosCallback(this->m_window, [](GLFWwindow *window, int x, int y) { 474 SharedData::windowPos = ImVec2(x, y); 475 }); 476 477 glfwSetWindowSizeCallback(this->m_window, [](GLFWwindow *window, int width, int height) { 478 SharedData::windowSize = ImVec2(width, height); 479 }); 480 481 glfwSetKeyCallback(this->m_window, [](GLFWwindow *window, int key, int scancode, int action, int mods) { 482 if (action == GLFW_PRESS) { 483 Window::s_currShortcut = { key, mods }; 484 auto &io = ImGui::GetIO(); 485 io.KeysDown[key] = true; 486 io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0; 487 io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0; 488 io.KeyAlt = (mods & GLFW_MOD_ALT) != 0; 489 } 490 else if (action == GLFW_RELEASE) { 491 auto &io = ImGui::GetIO(); 492 io.KeysDown[key] = false; 493 io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0; 494 io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0; 495 io.KeyAlt = (mods & GLFW_MOD_ALT) != 0; 496 } 497 }); 498 499 glfwSetDropCallback(this->m_window, [](GLFWwindow *window, int count, const char **paths) { 500 if (count != 1) 501 return; 502 503 View::postEvent(Events::FileDropped, paths[0]); 504 }); 505 506 glfwSetWindowCloseCallback(this->m_window, [](GLFWwindow *window) { 507 View::postEvent(Events::WindowClosing, window); 508 }); 509 510 511 glfwSetWindowSizeLimits(this->m_window, 720, 480, GLFW_DONT_CARE, GLFW_DONT_CARE); 512 513 if (gladLoadGL() == 0) 514 throw std::runtime_error("Failed to initialize OpenGL loader!"); 515 } 516 initImGui()517 void Window::initImGui() { 518 IMGUI_CHECKVERSION(); 519 520 GImGui = ImGui::CreateContext(); 521 522 ImGuiIO& io = ImGui::GetIO(); 523 ImGuiStyle& style = ImGui::GetStyle(); 524 525 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard; 526 #if !defined(OS_LINUX) 527 io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; 528 #endif 529 530 531 io.ConfigViewportsNoTaskBarIcon = false; 532 io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; 533 io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; 534 io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; 535 io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; 536 io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; 537 io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; 538 io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; 539 io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; 540 io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; 541 io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT; 542 io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; 543 io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; 544 io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; 545 io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; 546 io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; 547 io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER; 548 io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; 549 io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; 550 io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; 551 io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; 552 io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; 553 io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; 554 555 if (this->m_globalScale != 0.0f) 556 style.ScaleAllSizes(this->m_globalScale); 557 558 #if defined(OS_WINDOWS) 559 std::filesystem::path resourcePath = std::filesystem::path((SharedData::mainArgv)[0]).parent_path(); 560 #elif defined(OS_LINUX) || defined(OS_MACOS) 561 std::filesystem::path resourcePath = "/usr/share/ImHex"; 562 #else 563 std::filesystem::path resourcePath = ""; 564 #warning "Unsupported OS for custom font support" 565 #endif 566 567 if (!resourcePath.empty() && this->setFont(resourcePath / "font.ttf")) { 568 569 } 570 else if ((this->m_fontScale != 0.0f) && (this->m_fontScale != 1.0f)) { 571 io.Fonts->Clear(); 572 573 ImFontConfig cfg; 574 cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true; 575 cfg.SizePixels = 13.0f * this->m_fontScale; 576 io.Fonts->AddFontDefault(&cfg); 577 } 578 579 style.WindowMenuButtonPosition = ImGuiDir_None; 580 style.IndentSpacing = 10.0F; 581 582 // Install custom settings handler 583 ImGuiSettingsHandler handler; 584 handler.TypeName = "ImHex"; 585 handler.TypeHash = ImHashStr("ImHex"); 586 handler.ReadOpenFn = ImHexSettingsHandler_ReadOpenFn; 587 handler.ReadLineFn = ImHexSettingsHandler_ReadLine; 588 handler.WriteAllFn = ImHexSettingsHandler_WriteAll; 589 handler.UserData = this; 590 ImGui::GetCurrentContext()->SettingsHandlers.push_back(handler); 591 592 ImGui_ImplGlfw_InitForOpenGL(this->m_window, true); 593 ImGui_ImplOpenGL3_Init("#version 150"); 594 } 595 initPlugins()596 void Window::initPlugins() { 597 try { 598 auto pluginFolderPath = std::filesystem::path("/usr/local/share/imhex/plugins"); 599 PluginHandler::load(pluginFolderPath.string()); 600 } catch (std::runtime_error &e) { return; } 601 602 for (const auto &plugin : PluginHandler::getPlugins()) { 603 plugin.initializePlugin(); 604 } 605 } 606 deinitGLFW()607 void Window::deinitGLFW() { 608 glfwDestroyWindow(this->m_window); 609 glfwTerminate(); 610 } 611 deinitImGui()612 void Window::deinitImGui() { 613 ImGui_ImplOpenGL3_Shutdown(); 614 ImGui_ImplGlfw_Shutdown(); 615 ImGui::DestroyContext(); 616 } 617 deinitPlugins()618 void Window::deinitPlugins() { 619 PluginHandler::unload(); 620 } 621 622 }