diff --git a/external/ImGui/include/imgui_imhex_extensions.h b/external/ImGui/include/imgui_imhex_extensions.h index 25ca0065a..8367f30dc 100644 --- a/external/ImGui/include/imgui_imhex_extensions.h +++ b/external/ImGui/include/imgui_imhex_extensions.h @@ -18,6 +18,8 @@ enum ImGuiCustomCol { ImGuiCustomCol_ToolbarPurple, ImGuiCustomCol_ToolbarBrown, + ImGuiCustomCol_Highlight, + ImGuiCustomCol_COUNT }; @@ -54,6 +56,7 @@ namespace ImGui { void TextSpinner(const char* label); void Header(const char *label, bool firstEntry = false); + void HeaderColored(const char *label, ImColor color, bool firstEntry); void InfoTooltip(const char *text); diff --git a/external/ImGui/source/imgui_imhex_extensions.cpp b/external/ImGui/source/imgui_imhex_extensions.cpp index c04121f1b..0edbec71b 100644 --- a/external/ImGui/source/imgui_imhex_extensions.cpp +++ b/external/ImGui/source/imgui_imhex_extensions.cpp @@ -203,6 +203,13 @@ namespace ImGui { ImGui::Separator(); } + void HeaderColored(const char *label, ImColor color, bool firstEntry) { + if (!firstEntry) + ImGui::NewLine(); + ImGui::TextColored(color, "%s", label); + ImGui::Separator(); + } + void InfoTooltip(const char *text) { static double lastMoveTime; static ImGuiID lastHoveredID; @@ -250,6 +257,8 @@ namespace ImGui { colors[ImGuiCustomCol_ToolbarBlue] = ImColor(6, 83, 155); colors[ImGuiCustomCol_ToolbarPurple] = ImColor(103, 42, 120); colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119); + + colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155); } void StyleCustomColorsLight() { @@ -266,6 +275,8 @@ namespace ImGui { colors[ImGuiCustomCol_ToolbarBlue] = ImColor(6, 83, 155); colors[ImGuiCustomCol_ToolbarPurple] = ImColor(103, 42, 120); colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119); + + colors[ImGuiCustomCol_Highlight] = ImColor(41, 151, 112); } void StyleCustomColorsClassic() { @@ -282,6 +293,8 @@ namespace ImGui { colors[ImGuiCustomCol_ToolbarBlue] = ImColor(6, 83, 155); colors[ImGuiCustomCol_ToolbarPurple] = ImColor(103, 42, 120); colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119); + + colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155); } Texture LoadImageFromPath(const char *path) { diff --git a/plugins/builtin/source/content/tools_entries.cpp b/plugins/builtin/source/content/tools_entries.cpp index cddf35158..423e46515 100644 --- a/plugins/builtin/source/content/tools_entries.cpp +++ b/plugins/builtin/source/content/tools_entries.cpp @@ -12,6 +12,7 @@ namespace hex::plugin::builtin { namespace { + using namespace std::literals::string_literals; using namespace std::literals::chrono_literals; void drawDemangler() { @@ -496,6 +497,70 @@ namespace hex::plugin::builtin { } } + void drawWikiExplainer() { + static hex::Net net; + static std::string searchString(0xFFF, 0x00); + static std::string resultTitle, resultExtract; + static std::future> searchProcess; + static bool extendedSearch = false; + + constexpr static auto WikipediaApiUrl = "https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&explaintext&redirects=10&formatversion=2"; + + ImGui::Header("hex.builtin.tools.file_uploader.control"_lang, true); + + ImGui::BeginDisabled(searchProcess.valid() && searchProcess.wait_for(0s) != std::future_status::ready); + + bool startSearch = ImGui::InputText("##search", searchString.data(), searchString.capacity(), ImGuiInputTextFlags_EnterReturnsTrue); + ImGui::SameLine(); + startSearch = ImGui::Button("hex.builtin.tools.file_uploader.search"_lang) || startSearch; + + ImGui::EndDisabled(); + + if (startSearch) { + searchProcess = net.getString(WikipediaApiUrl + "&exintro"s + "&titles="s + net.encode(searchString)); + } + + ImGui::Header("hex.builtin.tools.file_uploader.results"_lang); + + if (ImGui::BeginChild("##summary", ImVec2(0, 300), true)) { + if (!resultTitle.empty() && !resultExtract.empty()) { + ImGui::HeaderColored(resultTitle.c_str(), ImGui::GetCustomColorVec4(ImGuiCustomCol_Highlight),true); + ImGui::TextWrapped("%s", resultExtract.c_str()); + } + } + ImGui::EndChild(); + + if (searchProcess.valid() && searchProcess.wait_for(0s) == std::future_status::ready) { + try { + auto response = searchProcess.get(); + if (response.code != 200) throw std::runtime_error("Invalid response"); + + auto json = nlohmann::json::parse(response.body); + + resultTitle = json["query"]["pages"][0]["title"]; + resultExtract = json["query"]["pages"][0]["extract"]; + + if (!extendedSearch && resultExtract.ends_with(':')) { + extendedSearch = true; + searchProcess = net.getString(WikipediaApiUrl + "&titles="s + net.encode(searchString)); + resultTitle.clear(); + resultExtract.clear(); + } else { + extendedSearch = false; + searchString.clear(); + } + } catch (...) { + resultTitle.clear(); + resultExtract.clear(); + extendedSearch = false; + searchProcess = { }; + + resultTitle = "???"; + resultExtract = "hex.builtin.tools.file_uploader.invalid_response"_lang.get(); + } + } + } + void registerToolEntries() { ContentRegistry::Tools::add("hex.builtin.tools.demangler", drawDemangler); ContentRegistry::Tools::add("hex.builtin.tools.ascii_table", drawASCIITable); @@ -505,6 +570,7 @@ namespace hex::plugin::builtin { ContentRegistry::Tools::add("hex.builtin.tools.base_converter", drawBaseConverter); ContentRegistry::Tools::add("hex.builtin.tools.permissions", drawPermissionsCalculator); ContentRegistry::Tools::add("hex.builtin.tools.file_uploader", drawFileUploader); + ContentRegistry::Tools::add("hex.builtin.tools.wiki_explain", drawWikiExplainer); } } \ No newline at end of file diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index e2963e8f0..29369beeb 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -546,8 +546,13 @@ namespace hex::plugin::builtin { { "hex.builtin.tools.file_uploader.done", "Fertig!" }, { "hex.builtin.tools.file_uploader.recent", "Letzte Uploads" }, { "hex.builtin.tools.file_uploader.tooltip", "Klicken zum Kopieren\nCTRL + Klicken zum öffnen" }, - { "hex.builtin.tools.file_uploader.invalid_response", "Ungültige Antwort von Anonfiles!"_lang }, - { "hex.builtin.tools.file_uploader.error", "Dateiupload fehlgeschlagen\n\nError Code: {0}"_lang }, + { "hex.builtin.tools.file_uploader.invalid_response", "Ungültige Antwort von Anonfiles!" }, + { "hex.builtin.tools.file_uploader.error", "Dateiupload fehlgeschlagen\n\nError Code: {0}" }, + { "hex.builtin.tools.wiki_explain", "Wikipedia Definition" }, + { "hex.builtin.tools.file_uploader.control", "Einstellungen" }, + { "hex.builtin.tools.file_uploader.search", "Suchen" }, + { "hex.builtin.tools.file_uploader.results", "Resultate" }, + { "hex.builtin.tools.file_uploader.invalid_response", "Ungültige Antwort von Wikipedia!" }, { "hex.builtin.setting.imhex", "ImHex" }, { "hex.builtin.setting.imhex.recent_files", "Kürzlich geöffnete Dateien" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index eefb07e2c..d866115d5 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -548,7 +548,11 @@ namespace hex::plugin::builtin { { "hex.builtin.tools.file_uploader.tooltip", "Click to copy\nCTRL + Click to open" }, { "hex.builtin.tools.file_uploader.invalid_response", "Invalid response from Anonfiles!" }, { "hex.builtin.tools.file_uploader.error", "Failed to upload file!\n\nError Code: {0}" }, - + { "hex.builtin.tools.wiki_explain", "Wikipedia term definitions" }, + { "hex.builtin.tools.file_uploader.control", "Control" }, + { "hex.builtin.tools.file_uploader.search", "Search" }, + { "hex.builtin.tools.file_uploader.results", "Results" }, + { "hex.builtin.tools.file_uploader.invalid_response", "Invalid response from Wikipedia!" }, { "hex.builtin.setting.imhex", "ImHex" }, { "hex.builtin.setting.imhex.recent_files", "Recent Files" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 8f13f3592..757d00b08 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -547,6 +547,11 @@ namespace hex::plugin::builtin { //{ "hex.builtin.tools.file_uploader.tooltip", "Click to copy\nCTRL + Click to open" }, //{ "hex.builtin.tools.file_uploader.invalid_response", "Invalid response from Anonfiles!" }, //{ "hex.builtin.tools.file_uploader.error", "Failed to upload file!\n\nError Code: {0}" }, + //{ "hex.builtin.tools.wiki_explain", "Wikipedia term definitions" }, + //{ "hex.builtin.tools.file_uploader.control", "Control" }, + //{ "hex.builtin.tools.file_uploader.search", "Search" }, + //{ "hex.builtin.tools.file_uploader.results", "Results" }, + //{ "hex.builtin.tools.file_uploader.invalid_response", "Invalid response from Wikipedia!" }, { "hex.builtin.setting.imhex", "ImHex" }, { "hex.builtin.setting.imhex.recent_files", "File recenti" }, diff --git a/plugins/libimhex/include/hex/helpers/net.hpp b/plugins/libimhex/include/hex/helpers/net.hpp index 6954dd66f..0cba73da8 100644 --- a/plugins/libimhex/include/hex/helpers/net.hpp +++ b/plugins/libimhex/include/hex/helpers/net.hpp @@ -28,6 +28,20 @@ namespace hex { std::future> uploadFile(const std::string &url, const std::filesystem::path &filePath); + [[nodiscard]] + std::string encode(const std::string &input) { + auto escapedString = curl_easy_escape(this->m_ctx, input.c_str(), std::strlen(input.c_str())); + + if (escapedString != nullptr) { + std::string output = escapedString; + curl_free(escapedString); + + return output; + } + + return { }; + } + [[nodiscard]] float getProgress() const { return this->m_progress; } diff --git a/source/views/view_bookmarks.cpp b/source/views/view_bookmarks.cpp index 45a63dedd..f69a3b027 100644 --- a/source/views/view_bookmarks.cpp +++ b/source/views/view_bookmarks.cpp @@ -115,9 +115,8 @@ namespace hex { ImGui::NewLine(); } } - - ImGui::EndChild(); } + ImGui::EndChild(); if (ImGui::Button("hex.view.bookmarks.button.jump"_lang)) EventManager::post(region); @@ -168,8 +167,8 @@ namespace hex { ProjectFile::markDirty(); } - ImGui::EndChild(); } + ImGui::EndChild(); } ImGui::End(); } diff --git a/source/views/view_disassembler.cpp b/source/views/view_disassembler.cpp index f654ccc03..8b88f0806 100644 --- a/source/views/view_disassembler.cpp +++ b/source/views/view_disassembler.cpp @@ -244,8 +244,8 @@ namespace hex { break; } - ImGui::EndChild(); } + ImGui::EndChild(); ImGui::Disabled([this] { if (ImGui::Button("hex.view.disassembler.disassemble"_lang)) diff --git a/source/views/view_hashes.cpp b/source/views/view_hashes.cpp index ae3e99cad..ea9b1fa36 100644 --- a/source/views/view_hashes.cpp +++ b/source/views/view_hashes.cpp @@ -223,8 +223,8 @@ namespace hex { this->m_shouldInvalidate = false; } - ImGui::EndChild(); } + ImGui::EndChild(); } ImGui::End(); } diff --git a/source/views/view_help.cpp b/source/views/view_help.cpp index 0ca9dfdd9..28eb63851 100644 --- a/source/views/view_help.cpp +++ b/source/views/view_help.cpp @@ -40,8 +40,8 @@ namespace hex { ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.2F, 0.2F, 0.2F, 0.3F)); if (ImGui::BeginChild(id.c_str(), ImVec2(-1, ImGui::CalcTextSize(code.c_str()).y))) { ImGui::Text("%s", code.c_str()); - ImGui::EndChild(); } + ImGui::EndChild(); ImGui::NewLine(); ImGui::PopStyleColor(); diff --git a/source/views/view_information.cpp b/source/views/view_information.cpp index d74e99b60..48f395301 100644 --- a/source/views/view_information.cpp +++ b/source/views/view_information.cpp @@ -241,8 +241,8 @@ namespace hex { } } - ImGui::EndChild(); } + ImGui::EndChild(); } ImGui::End(); } diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index 21b5a2c24..d1f6c9e19 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -258,8 +258,8 @@ namespace hex { ImGui::PopStyleColor(); } - ImGui::EndChild(); } + ImGui::EndChild(); ImGui::PopStyleColor(1); ImGui::Disabled([this]{ diff --git a/source/views/view_strings.cpp b/source/views/view_strings.cpp index e803c3fff..2caff32af 100644 --- a/source/views/view_strings.cpp +++ b/source/views/view_strings.cpp @@ -190,8 +190,8 @@ namespace hex { if (ImGui::Button("hex.view.strings.demangle.copy"_lang)) ImGui::SetClipboardText(this->m_demangledName.c_str()); - ImGui::EndChild(); } + ImGui::EndChild(); ImGui::EndPopup(); } }