From 96fe608d608e4deecd538bfa1fa92471f91649e0 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Tue, 26 Dec 2023 00:22:47 +0100 Subject: [PATCH] impr: Switch most usages of modals over to toasts --- lib/external/libwolv | 2 +- .../include/hex/api/event_manager.hpp | 5 --- main/gui/source/window/window.cpp | 39 +++++++---------- .../builtin/source/content/achievements.cpp | 3 +- plugins/builtin/source/content/events.cpp | 23 +++------- .../builtin/source/content/global_actions.cpp | 8 ++-- .../source/content/helpers/notification.cpp | 6 +-- .../source/content/main_menu_items.cpp | 32 +++++++------- .../content/providers/disk_provider.cpp | 9 ++-- .../providers/process_memory_provider.cpp | 6 ++- plugins/builtin/source/content/recent.cpp | 4 +- .../content/tools/file_tool_combiner.cpp | 9 ++-- .../content/tools/file_tool_shredder.cpp | 7 ++-- .../content/tools/file_tool_splitter.cpp | 11 ++--- plugins/builtin/source/content/ui_items.cpp | 7 ++-- .../content/views/view_data_processor.cpp | 4 +- .../source/content/views/view_information.cpp | 4 +- .../content/views/view_provider_settings.cpp | 8 ++-- .../source/content/views/view_store.cpp | 3 +- plugins/script_loader/CMakeLists.txt | 3 ++ .../script_loader/source/script_api/v1/ui.cpp | 4 +- .../ui/include/toasts/toast_notification.hpp | 42 ++++++++++++------- plugins/windows/CMakeLists.txt | 1 + .../windows/source/views/view_tty_console.cpp | 6 ++- .../source/content/views/view_yara.cpp | 4 +- 25 files changed, 129 insertions(+), 121 deletions(-) diff --git a/lib/external/libwolv b/lib/external/libwolv index b998f3d47..5b54c3b81 160000 --- a/lib/external/libwolv +++ b/lib/external/libwolv @@ -1 +1 @@ -Subproject commit b998f3d47940970d0ff74451ea6a7ca06c803af5 +Subproject commit 5b54c3b814c784500fb40fb6cfe55f8aa7187fcb diff --git a/lib/libimhex/include/hex/api/event_manager.hpp b/lib/libimhex/include/hex/api/event_manager.hpp index 6b3e64072..c552b6e2b 100644 --- a/lib/libimhex/include/hex/api/event_manager.hpp +++ b/lib/libimhex/include/hex/api/event_manager.hpp @@ -289,11 +289,6 @@ namespace hex { EVENT_DEF(RequestCreateProvider, std::string, bool, bool, hex::prv::Provider **); EVENT_DEF(RequestInitThemeHandlers); - EVENT_DEF(RequestOpenInfoPopup, const std::string); - EVENT_DEF(RequestOpenErrorPopup, const std::string); - EVENT_DEF(RequestOpenFatalPopup, const std::string); - - /** * @brief Send an event to the main Imhex instance */ diff --git a/main/gui/source/window/window.cpp b/main/gui/source/window/window.cpp index 9b6c4e96e..446e1b3de 100644 --- a/main/gui/source/window/window.cpp +++ b/main/gui/source/window/window.cpp @@ -672,7 +672,6 @@ namespace hex { // Draw popup stack { - static bool popupDisplaying = false; static bool positionSet = false; static bool sizeSet = false; static double popupDelay = -2.0; @@ -724,7 +723,6 @@ namespace hex { const auto createPopup = [&](bool displaying) { if (displaying) { currPopup->drawContent(); - popupDisplaying = true; if (ImGui::GetWindowSize().x > ImGui::GetStyle().FramePadding.x * 10) sizeSet = true; @@ -742,8 +740,6 @@ namespace hex { } ImGui::EndPopup(); - } else { - popupDisplaying = false; } }; @@ -752,7 +748,7 @@ namespace hex { else createPopup(ImGui::BeginPopup(name, flags)); - if (!popupDisplaying || currPopup->shouldClose()) { + if (currPopup->shouldClose()) { log::debug("Closing popup '{}'", name); positionSet = sizeSet = false; @@ -763,41 +759,38 @@ namespace hex { // Draw Toasts { - static std::unique_ptr currToast; - if (currToast == nullptr) { - if (auto &queuedToasts = impl::ToastBase::getQueuedToasts(); !queuedToasts.empty()) { - currToast = std::move(queuedToasts.front()); - queuedToasts.pop_front(); - - currToast->setAppearTime(ImGui::GetTime()); - } - } else { + u32 index = 0; + for (const auto &toast : impl::ToastBase::getQueuedToasts() | std::views::take(4)) { + const auto toastHeight = 60_scaled; ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5_scaled); - ImGui::SetNextWindowSize(scaled({ 280, 60 })); - ImGui::SetNextWindowPos((ImHexApi::System::getMainWindowPosition() + ImHexApi::System::getMainWindowSize()) - scaled({ 10, 10 }), ImGuiCond_Always, ImVec2(1, 1)); - if (ImGui::Begin("##Toast", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoInputs)) { + 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)) { auto drawList = ImGui::GetWindowDrawList(); const auto min = ImGui::GetWindowPos(); const auto max = min + ImGui::GetWindowSize(); drawList->PushClipRect(min, min + scaled({ 5, 60 })); - drawList->AddRectFilled(min, max, currToast->getColor(), 5_scaled); + drawList->AddRectFilled(min, max, toast->getColor(), 5_scaled); drawList->PopClipRect(); ImGui::Indent(); - currToast->draw(); + toast->draw(); ImGui::Unindent(); + + if (ImGui::IsWindowHovered() || toast->getAppearTime() <= 0) + toast->setAppearTime(ImGui::GetTime()); } ImGui::End(); ImGui::PopStyleVar(); - if ((currToast->getAppearTime() + impl::ToastBase::VisibilityTime) < ImGui::GetTime()) { - currToast.reset(); - } + index += 1; } - + std::erase_if(impl::ToastBase::getQueuedToasts(), [](const auto &toast){ + return toast->getAppearTime() > 0 && (toast->getAppearTime() + impl::ToastBase::VisibilityTime) < ImGui::GetTime(); + }); } // Run all deferred calls diff --git a/plugins/builtin/source/content/achievements.cpp b/plugins/builtin/source/content/achievements.cpp index ff344cea8..ee06a4dac 100644 --- a/plugins/builtin/source/content/achievements.cpp +++ b/plugins/builtin/source/content/achievements.cpp @@ -4,6 +4,7 @@ #include +#include #include #include @@ -275,7 +276,7 @@ namespace hex::plugin::builtin { if (input == password) achievement.setUnlocked(true); else - ui::PopupInfo::open("The password you entered was incorrect."); + ui::ToastWarning::open("The password you entered was incorrect."); }); }); diff --git a/plugins/builtin/source/content/events.cpp b/plugins/builtin/source/content/events.cpp index 26ddb7150..7a6672d17 100644 --- a/plugins/builtin/source/content/events.cpp +++ b/plugins/builtin/source/content/events.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -26,7 +27,7 @@ namespace hex::plugin::builtin { if (auto *fileProvider = dynamic_cast(provider); fileProvider != nullptr) { fileProvider->setPath(path); if (!provider->open() || !provider->isAvailable()) { - ui::PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage())); + ui::ToastError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage())); TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); }); } else { EventProviderOpened::post(fileProvider); @@ -104,7 +105,7 @@ namespace hex::plugin::builtin { fs::openFileBrowser(fs::DialogMode::Open, { }, [](const auto &path) { if (path.extension() == ".hexproj") { if (!ProjectFile::load(path)) { - ui::PopupError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path))); + ui::ToastError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path))); } } else { FileProvider* newProvider = static_cast( @@ -128,7 +129,7 @@ namespace hex::plugin::builtin { fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} }, [](const auto &path) { if (!ProjectFile::load(path)) { - ui::PopupError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path))); + ui::ToastError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path))); } }); } @@ -149,7 +150,7 @@ namespace hex::plugin::builtin { return; } if (!provider->open()) { - ui::PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage())); + ui::ToastError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage())); TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); }); return; } @@ -158,7 +159,7 @@ namespace hex::plugin::builtin { } else if (!provider->hasLoadInterface()) { if (!provider->open() || !provider->isAvailable()) { - ui::PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage())); + ui::ToastError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage())); TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); }); return; } @@ -171,18 +172,6 @@ namespace hex::plugin::builtin { ImHexApi::HexEditor::impl::setCurrentSelection(region); }); - RequestOpenInfoPopup::subscribe([](const std::string &message) { - ui::PopupInfo::open(message); - }); - - RequestOpenErrorPopup::subscribe([](const std::string &message) { - ui::PopupError::open(message); - }); - - RequestOpenFatalPopup::subscribe([](const std::string &message) { - ui::PopupFatal::open(message); - }); - fs::setFileBrowserErrorCallback([](const std::string& errMsg){ #if defined(NFD_PORTAL) ui::PopupError::open(hex::format("hex.builtin.popup.error.file_dialog.portal"_lang, errMsg)); diff --git a/plugins/builtin/source/content/global_actions.cpp b/plugins/builtin/source/content/global_actions.cpp index ad2484f9f..90bb8d35b 100644 --- a/plugins/builtin/source/content/global_actions.cpp +++ b/plugins/builtin/source/content/global_actions.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include @@ -13,7 +13,7 @@ namespace hex::plugin::builtin { fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} }, [](const auto &path) { if (!ProjectFile::load(path)) { - ui::PopupError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path))); + ui::ToastError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path))); } }); } @@ -21,7 +21,7 @@ namespace hex::plugin::builtin { void saveProject() { if (ImHexApi::Provider::isValid() && ProjectFile::hasPath()) { if (!ProjectFile::store()) { - ui::PopupError::open("hex.builtin.popup.error.project.save"_lang); + ui::ToastError::open("hex.builtin.popup.error.project.save"_lang); } else { log::debug("Project saved"); } @@ -36,7 +36,7 @@ namespace hex::plugin::builtin { } if (!ProjectFile::store(path)) { - ui::PopupError::open("hex.builtin.popup.error.project.save"_lang); + ui::ToastError::open("hex.builtin.popup.error.project.save"_lang); } }); } diff --git a/plugins/builtin/source/content/helpers/notification.cpp b/plugins/builtin/source/content/helpers/notification.cpp index 1cb2fe37b..7bcecb005 100644 --- a/plugins/builtin/source/content/helpers/notification.cpp +++ b/plugins/builtin/source/content/helpers/notification.cpp @@ -1,16 +1,16 @@ #include -#include +#include namespace hex::plugin::builtin { void showError(const std::string& message){ - ui::PopupError::open(message); + ui::ToastError::open(message); log::error(message); } void showWarning(const std::string& message){ - ui::PopupWarning::open(message); + ui::ToastWarning::open(message); log::warn(message); } } diff --git a/plugins/builtin/source/content/main_menu_items.cpp b/plugins/builtin/source/content/main_menu_items.cpp index 797537678..c3afd9bb2 100644 --- a/plugins/builtin/source/content/main_menu_items.cpp +++ b/plugins/builtin/source/content/main_menu_items.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include @@ -50,19 +50,19 @@ namespace hex::plugin::builtin { TaskManager::doLater([error]{ switch (error) { case IPSError::InvalidPatchHeader: - ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.invalid_patch_header_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.export.ips.popup.invalid_patch_header_error"_lang); break; case IPSError::AddressOutOfRange: - ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.address_out_of_range_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.export.ips.popup.address_out_of_range_error"_lang); break; case IPSError::PatchTooLarge: - ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.patch_too_large_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.export.ips.popup.patch_too_large_error"_lang); break; case IPSError::InvalidPatchFormat: - ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.invalid_patch_format_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.export.ips.popup.invalid_patch_format_error"_lang); break; case IPSError::MissingEOF: - ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.missing_eof_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.export.ips.popup.missing_eof_error"_lang); break; } }); @@ -77,7 +77,7 @@ namespace hex::plugin::builtin { fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) { wolv::io::File inputFile(path, wolv::io::File::Mode::Read); if (!inputFile.isValid()) { - ui::PopupError::open("hex.builtin.menu.file.import.base64.popup.open_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.import.base64.popup.open_error"_lang); return; } @@ -87,19 +87,19 @@ namespace hex::plugin::builtin { auto data = crypt::decode64(base64); if (data.empty()) - ui::PopupError::open("hex.builtin.menu.file.import.base64.popup.import_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.import.base64.popup.import_error"_lang); else { fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const std::fs::path &path) { wolv::io::File outputFile(path, wolv::io::File::Mode::Create); if (!outputFile.isValid()) - ui::PopupError::open("hex.builtin.menu.file.import.base64.popup.import_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.import.base64.popup.import_error"_lang); outputFile.writeVector(data); }); } } else { - ui::PopupError::open("hex.builtin.popup.file_open_error"_lang); + ui::ToastError::open("hex.builtin.popup.file_open_error"_lang); } }); } @@ -163,7 +163,7 @@ namespace hex::plugin::builtin { auto patchData = wolv::io::File(path, wolv::io::File::Mode::Read).readVector(); if (patchData.size() != provider->getActualSize()) { - ui::PopupError::open("hex.builtin.menu.file.import.modified_file.popup.invalid_size"_lang); + ui::ToastError::open("hex.builtin.menu.file.import.modified_file.popup.invalid_size"_lang); return; } @@ -203,7 +203,7 @@ namespace hex::plugin::builtin { wolv::io::File outputFile(path, wolv::io::File::Mode::Create); if (!outputFile.isValid()) { TaskManager::doLater([] { - ui::PopupError::open("hex.builtin.menu.file.export.base64.popup.export_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.export.base64.popup.export_error"_lang); }); return; } @@ -238,7 +238,7 @@ namespace hex::plugin::builtin { wolv::io::File file(path, wolv::io::File::Mode::Create); if (!file.isValid()) { TaskManager::doLater([] { - ui::PopupError::open("hex.builtin.menu.file.export.as_language.popup.export_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.export.as_language.popup.export_error"_lang); }); return; } @@ -269,7 +269,7 @@ namespace hex::plugin::builtin { fs::openFileBrowser(fs::DialogMode::Save, { { "Markdown File", "md" }}, [&data](const auto &path) { auto file = wolv::io::File(path, wolv::io::File::Mode::Create); if (!file.isValid()) { - ui::PopupError::open("hex.builtin.menu.file.export.report.popup.export_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.export.report.popup.export_error"_lang); return; } @@ -302,7 +302,7 @@ namespace hex::plugin::builtin { fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) { auto file = wolv::io::File(path, wolv::io::File::Mode::Create); if (!file.isValid()) { - ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.export_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.export.ips.popup.export_error"_lang); return; } @@ -341,7 +341,7 @@ namespace hex::plugin::builtin { fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) { auto file = wolv::io::File(path, wolv::io::File::Mode::Create); if (!file.isValid()) { - ui::PopupError::open("hex.builtin.menu.file.export.ips.popup.export_error"_lang); + ui::ToastError::open("hex.builtin.menu.file.export.ips.popup.export_error"_lang); return; } diff --git a/plugins/builtin/source/content/providers/disk_provider.cpp b/plugins/builtin/source/content/providers/disk_provider.cpp index 42e4a8097..be12b2657 100644 --- a/plugins/builtin/source/content/providers/disk_provider.cpp +++ b/plugins/builtin/source/content/providers/disk_provider.cpp @@ -155,8 +155,10 @@ namespace hex::plugin::builtin { m_diskHandle = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); m_writable = false; - if (m_diskHandle == INVALID_HANDLE_VALUE) + if (m_diskHandle == INVALID_HANDLE_VALUE) { + this->setErrorMessage(std::system_category().message(::GetLastError())); return false; + } } { @@ -178,6 +180,7 @@ namespace hex::plugin::builtin { } if (m_diskHandle == nullptr || m_diskHandle == INVALID_HANDLE_VALUE) { + this->setErrorMessage(std::system_category().message(::GetLastError())); m_readable = false; m_diskHandle = nullptr; CloseHandle(m_diskHandle); @@ -220,9 +223,9 @@ namespace hex::plugin::builtin { #if defined(OS_WINDOWS) if (m_diskHandle != INVALID_HANDLE_VALUE) - ::CloseHandle(m_diskHandle); + ::CloseHandle(m_diskHandle); - m_diskHandle = INVALID_HANDLE_VALUE; + m_diskHandle = INVALID_HANDLE_VALUE; #else diff --git a/plugins/builtin/source/content/providers/process_memory_provider.cpp b/plugins/builtin/source/content/providers/process_memory_provider.cpp index 2964d680c..2b39c8f79 100644 --- a/plugins/builtin/source/content/providers/process_memory_provider.cpp +++ b/plugins/builtin/source/content/providers/process_memory_provider.cpp @@ -16,6 +16,8 @@ #include #include +#include + #include #include #include @@ -294,7 +296,7 @@ namespace hex::plugin::builtin { if (loadLibraryW != nullptr) { if (auto threadHandle = CreateRemoteThread(m_processHandle, nullptr, 0, loadLibraryW, pathAddress, 0, nullptr); threadHandle != nullptr) { WaitForSingleObject(threadHandle, INFINITE); - RequestOpenErrorPopup::post(hex::format("hex.builtin.provider.process_memory.utils.inject_dll.success"_lang, path.filename().string())); + ui::ToastInfo::open(hex::format("hex.builtin.provider.process_memory.utils.inject_dll.success"_lang, path.filename().string())); this->reloadProcessModules(); CloseHandle(threadHandle); return; @@ -303,7 +305,7 @@ namespace hex::plugin::builtin { } } - RequestOpenErrorPopup::post(hex::format("hex.builtin.provider.process_memory.utils.inject_dll.failure"_lang, path.filename().string())); + ui::ToastError::open(hex::format("hex.builtin.provider.process_memory.utils.inject_dll.failure"_lang, path.filename().string())); }); } #endif diff --git a/plugins/builtin/source/content/recent.cpp b/plugins/builtin/source/content/recent.cpp index d7958f6b8..04409a04e 100644 --- a/plugins/builtin/source/content/recent.cpp +++ b/plugins/builtin/source/content/recent.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include namespace hex::plugin::builtin::recent { @@ -224,7 +224,7 @@ namespace hex::plugin::builtin::recent { provider->loadSettings(recentEntry.data); if (!provider->open() || !provider->isAvailable()) { - ui::PopupError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage())); + ui::ToastError::open(hex::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage())); TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); }); return; } diff --git a/plugins/builtin/source/content/tools/file_tool_combiner.cpp b/plugins/builtin/source/content/tools/file_tool_combiner.cpp index 32f02c7d7..34b0b4ed9 100644 --- a/plugins/builtin/source/content/tools/file_tool_combiner.cpp +++ b/plugins/builtin/source/content/tools/file_tool_combiner.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -9,7 +10,7 @@ #include #include -#include +#include #include @@ -113,7 +114,7 @@ namespace hex::plugin::builtin { wolv::io::File output(outputPath, wolv::io::File::Mode::Create); if (!output.isValid()) { - ui::PopupError::open("hex.builtin.tools.file_tools.combiner.error.open_output"_lang); + ui::ToastError::open("hex.builtin.tools.file_tools.combiner.error.open_output"_lang); return; } @@ -126,7 +127,7 @@ namespace hex::plugin::builtin { wolv::io::File input(file, wolv::io::File::Mode::Read); if (!input.isValid()) { - ui::PopupError::open(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, wolv::util::toUTF8String(file))); + ui::ToastError::open(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, wolv::util::toUTF8String(file))); return; } @@ -142,7 +143,7 @@ namespace hex::plugin::builtin { selectedIndex = 0; outputPath.clear(); - ui::PopupInfo::open("hex.builtin.tools.file_tools.combiner.success"_lang); + ui::ToastInfo::open("hex.builtin.tools.file_tools.combiner.success"_lang); }); } } diff --git a/plugins/builtin/source/content/tools/file_tool_shredder.cpp b/plugins/builtin/source/content/tools/file_tool_shredder.cpp index 4bee6bd02..619dc8340 100644 --- a/plugins/builtin/source/content/tools/file_tool_shredder.cpp +++ b/plugins/builtin/source/content/tools/file_tool_shredder.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -7,7 +8,7 @@ #include #include -#include +#include #include #include @@ -54,7 +55,7 @@ namespace hex::plugin::builtin { wolv::io::File file(selectedFile, wolv::io::File::Mode::Write); if (!file.isValid()) { - ui::PopupError::open("hex.builtin.tools.file_tools.shredder.error.open"_lang); + ui::ToastError::open("hex.builtin.tools.file_tools.shredder.error.open"_lang); return; } @@ -128,7 +129,7 @@ namespace hex::plugin::builtin { file.remove(); - ui::PopupInfo::open("hex.builtin.tools.file_tools.shredder.success"_lang); + ui::ToastInfo::open("hex.builtin.tools.file_tools.shredder.success"_lang); }); } } diff --git a/plugins/builtin/source/content/tools/file_tool_splitter.cpp b/plugins/builtin/source/content/tools/file_tool_splitter.cpp index 1208a4323..b0f628a55 100644 --- a/plugins/builtin/source/content/tools/file_tool_splitter.cpp +++ b/plugins/builtin/source/content/tools/file_tool_splitter.cpp @@ -3,13 +3,14 @@ #include #include #include +#include #include #include #include -#include +#include #include #include @@ -101,12 +102,12 @@ namespace hex::plugin::builtin { wolv::io::File file(selectedFile, wolv::io::File::Mode::Read); if (!file.isValid()) { - ui::PopupError::open("hex.builtin.tools.file_tools.splitter.picker.error.open"_lang); + ui::ToastError::open("hex.builtin.tools.file_tools.splitter.picker.error.open"_lang); return; } if (file.getSize() < splitSize) { - ui::PopupError::open("hex.builtin.tools.file_tools.splitter.picker.error.size"_lang); + ui::ToastError::open("hex.builtin.tools.file_tools.splitter.picker.error.size"_lang); return; } @@ -122,7 +123,7 @@ namespace hex::plugin::builtin { wolv::io::File partFile(path, wolv::io::File::Mode::Create); if (!partFile.isValid()) { - ui::PopupError::open(hex::format("hex.builtin.tools.file_tools.splitter.picker.error.create"_lang, index)); + ui::ToastError::open(hex::format("hex.builtin.tools.file_tools.splitter.picker.error.create"_lang, index)); return; } @@ -135,7 +136,7 @@ namespace hex::plugin::builtin { index++; } - ui::PopupInfo::open("hex.builtin.tools.file_tools.splitter.picker.success"_lang); + ui::ToastInfo::open("hex.builtin.tools.file_tools.splitter.picker.success"_lang); }); } } diff --git a/plugins/builtin/source/content/ui_items.cpp b/plugins/builtin/source/content/ui_items.cpp index 09620a0f8..6eda7cee8 100644 --- a/plugins/builtin/source/content/ui_items.cpp +++ b/plugins/builtin/source/content/ui_items.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -13,7 +14,7 @@ #include #include -#include +#include namespace hex::plugin::builtin { @@ -43,10 +44,10 @@ namespace hex::plugin::builtin { } static void drawGlobalPopups() { - // Task exception popup + // Task exception toast for (const auto &task : TaskManager::getRunningTasks()) { if (task->hadException()) { - ui::PopupError::open(hex::format("hex.builtin.popup.error.task_exception"_lang, Lang(task->getUnlocalizedName()), task->getExceptionMessage())); + ui::ToastError::open(hex::format("hex.builtin.popup.error.task_exception"_lang, Lang(task->getUnlocalizedName()), task->getExceptionMessage())); task->clearException(); break; } diff --git a/plugins/builtin/source/content/views/view_data_processor.cpp b/plugins/builtin/source/content/views/view_data_processor.cpp index c36ee7d34..a7df18cc2 100644 --- a/plugins/builtin/source/content/views/view_data_processor.cpp +++ b/plugins/builtin/source/content/views/view_data_processor.cpp @@ -1,5 +1,5 @@ #include "content/views/view_data_processor.hpp" -#include +#include #include #include @@ -1194,7 +1194,7 @@ namespace hex::plugin::builtin { m_updateNodePositions = true; } catch (nlohmann::json::exception &e) { - ui::PopupError::open(hex::format("Failed to load nodes: {}", e.what())); + ui::ToastError::open(hex::format("Failed to load nodes: {}", e.what())); } } diff --git a/plugins/builtin/source/content/views/view_information.cpp b/plugins/builtin/source/content/views/view_information.cpp index 65d2006e4..cf8f32626 100644 --- a/plugins/builtin/source/content/views/view_information.cpp +++ b/plugins/builtin/source/content/views/view_information.cpp @@ -14,7 +14,7 @@ #include -#include +#include namespace hex::plugin::builtin { @@ -48,7 +48,7 @@ namespace hex::plugin::builtin { ContentRegistry::FileHandler::add({ ".mgc" }, [](const auto &path) { for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Magic)) { if (wolv::io::fs::copyFile(path, destPath / path.filename(), std::fs::copy_options::overwrite_existing)) { - ui::PopupInfo::open("hex.builtin.view.information.magic_db_added"_lang); + ui::ToastInfo::open("hex.builtin.view.information.magic_db_added"_lang); return true; } } diff --git a/plugins/builtin/source/content/views/view_provider_settings.cpp b/plugins/builtin/source/content/views/view_provider_settings.cpp index 61515200b..f95d73c79 100644 --- a/plugins/builtin/source/content/views/view_provider_settings.cpp +++ b/plugins/builtin/source/content/views/view_provider_settings.cpp @@ -1,7 +1,9 @@ #include "content/views/view_provider_settings.hpp" -#include #include +#include + +#include namespace hex::plugin::builtin { @@ -49,9 +51,9 @@ namespace hex::plugin::builtin { ImGui::CloseCurrentPopup(); auto errorMessage = provider->getErrorMessage(); if (errorMessage.empty()) { - ui::PopupError::open("hex.builtin.view.provider_settings.load_error"_lang); + ui::ToastError::open("hex.builtin.view.provider_settings.load_error"_lang); } else { - ui::PopupError::open(hex::format("hex.builtin.view.provider_settings.load_error_details"_lang, errorMessage)); + ui::ToastError::open(hex::format("hex.builtin.view.provider_settings.load_error_details"_lang, errorMessage)); } TaskManager::doLater([=] { ImHexApi::Provider::remove(provider); }); } diff --git a/plugins/builtin/source/content/views/view_store.cpp b/plugins/builtin/source/content/views/view_store.cpp index f83d76cc0..8e6d07dca 100644 --- a/plugins/builtin/source/content/views/view_store.cpp +++ b/plugins/builtin/source/content/views/view_store.cpp @@ -6,6 +6,7 @@ #include #include +#include #include @@ -310,7 +311,7 @@ namespace hex::plugin::builtin { } if (!downloading) { - ui::PopupError::open("hex.builtin.view.store.download_error"_lang); + ui::ToastError::open("hex.builtin.view.store.download_error"_lang); return false; } diff --git a/plugins/script_loader/CMakeLists.txt b/plugins/script_loader/CMakeLists.txt index baa8ffcd9..521cc86b7 100644 --- a/plugins/script_loader/CMakeLists.txt +++ b/plugins/script_loader/CMakeLists.txt @@ -12,6 +12,9 @@ add_imhex_plugin( INCLUDES include + + LIBRARIES + ui ) if (CoreClrEmbed_FOUND) diff --git a/plugins/script_loader/source/script_api/v1/ui.cpp b/plugins/script_loader/source/script_api/v1/ui.cpp index e484ff591..5cbfad20e 100644 --- a/plugins/script_loader/source/script_api/v1/ui.cpp +++ b/plugins/script_loader/source/script_api/v1/ui.cpp @@ -8,6 +8,8 @@ #include +#include + using namespace hex; #define VERSION V1 @@ -114,7 +116,7 @@ private: }; SCRIPT_API(void showMessageBox, const char *message) { - hex::RequestOpenInfoPopup::post(message); + ui::PopupInfo::open(message); } SCRIPT_API(void showInputTextBox, const char *title, const char *message, char *buffer, u32 bufferSize) { diff --git a/plugins/ui/include/toasts/toast_notification.hpp b/plugins/ui/include/toasts/toast_notification.hpp index 5979e00af..ead7c5ebc 100644 --- a/plugins/ui/include/toasts/toast_notification.hpp +++ b/plugins/ui/include/toasts/toast_notification.hpp @@ -7,49 +7,59 @@ #include #include +#include + namespace hex::ui { namespace impl { template struct ToastNotification : Toast { - ToastNotification(ImColor color, const char *icon, UnlocalizedString title, UnlocalizedString message) - : Toast(color), m_icon(icon), m_title(std::move(title)), m_message(std::move(message)) {} + ToastNotification(ImColor color, const char *icon, UnlocalizedString unlocalizedTitle, std::string message) + : Toast(color), m_icon(icon), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_message(std::move(message)) {} void drawContent() final { + if (ImGui::IsWindowHovered()) { + if (ImGui::BeginTooltip()) { + ImGuiExt::Header(Lang(m_unlocalizedTitle), true); + ImGui::PushTextWrapPos(300_scaled); + ImGui::TextUnformatted(m_message.c_str()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + } + ImGuiExt::TextFormattedColored(this->getColor(), "{}", m_icon); ImGui::SameLine(); - ImGui::PushFont(ImHexApi::Fonts::Bold()); - { - ImGuiExt::TextFormatted("{}", hex::limitStringLength(Lang(m_title).get(), 30)); - } - ImGui::PopFont(); + + ImGuiExt::TextFormatted("{}", hex::limitStringLength(Lang(m_unlocalizedTitle).get(), 30)); ImGui::Separator(); - ImGuiExt::TextFormattedWrapped("{}", hex::limitStringLength(Lang(m_message).get(), 60)); + ImGuiExt::TextFormattedWrapped("{}", hex::limitStringLength(m_message, 60)); } private: const char *m_icon; - UnlocalizedString m_title, m_message; + UnlocalizedString m_unlocalizedTitle; + std::string m_message; }; } struct ToastInfo : impl::ToastNotification { - ToastInfo(UnlocalizedString title, UnlocalizedString message) - : ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerInfo), ICON_VS_INFO, std::move(title), std::move(message)) {} + ToastInfo(std::string message) + : ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerInfo), ICON_VS_INFO, "hex.ui.common.info", std::move(message)) {} }; - struct ToastWarn : impl::ToastNotification { - ToastWarn(UnlocalizedString title, UnlocalizedString message) - : ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerWarning), ICON_VS_WARNING, std::move(title), std::move(message)) {} + struct ToastWarning : impl::ToastNotification { + ToastWarning(std::string message) + : ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerWarning), ICON_VS_WARNING, "hex.ui.common.warning", std::move(message)) {} }; struct ToastError : impl::ToastNotification { - ToastError(UnlocalizedString title, UnlocalizedString message) - : ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerError), ICON_VS_ERROR, std::move(title), std::move(message)) {} + ToastError(std::string message) + : ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerError), ICON_VS_ERROR, "hex.ui.common.error", std::move(message)) {} }; } diff --git a/plugins/windows/CMakeLists.txt b/plugins/windows/CMakeLists.txt index ea8f49751..bac86b895 100644 --- a/plugins/windows/CMakeLists.txt +++ b/plugins/windows/CMakeLists.txt @@ -16,6 +16,7 @@ if (WIN32) INCLUDES include LIBRARIES + ui ${JTHREAD_LIBRARIES} ) diff --git a/plugins/windows/source/views/view_tty_console.cpp b/plugins/windows/source/views/view_tty_console.cpp index cafaebd6e..711ecc8f3 100644 --- a/plugins/windows/source/views/view_tty_console.cpp +++ b/plugins/windows/source/views/view_tty_console.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include @@ -85,7 +87,7 @@ namespace hex::plugin::windows { if (m_portHandle == INVALID_HANDLE_VALUE) { if (ImGui::Button("hex.windows.view.tty_console.connect"_lang)) if (!this->connect()) - RequestOpenErrorPopup::post("hex.windows.view.tty_console.connect_error"_lang); + ui::ToastError::open("hex.windows.view.tty_console.connect_error"_lang); } else { if (ImGui::Button("hex.windows.view.tty_console.disconnect"_lang)) this->disconnect(); @@ -184,7 +186,7 @@ namespace hex::plugin::windows { bool ViewTTYConsole::connect() { if (m_comPorts.empty() || static_cast(m_selectedPort) >= m_comPorts.size()) { - RequestOpenErrorPopup::post("hex.windows.view.tty_console.no_available_port"_lang); + ui::ToastError::open("hex.windows.view.tty_console.no_available_port"_lang); return true; // If false, connect_error error popup will override this error popup } m_portHandle = ::CreateFile((R"(\\.\)" + m_comPorts[m_selectedPort].first).c_str(), diff --git a/plugins/yara_rules/source/content/views/view_yara.cpp b/plugins/yara_rules/source/content/views/view_yara.cpp index 899fc883b..36f139bfe 100644 --- a/plugins/yara_rules/source/content/views/view_yara.cpp +++ b/plugins/yara_rules/source/content/views/view_yara.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include // 's RE type has a zero-sized array, which is not allowed in ISO C++. @@ -33,7 +33,7 @@ namespace hex::plugin::yara { ContentRegistry::FileHandler::add({ ".yar", ".yara" }, [](const auto &path) { for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Yara)) { if (wolv::io::fs::copyFile(path, destPath / path.filename(), std::fs::copy_options::overwrite_existing)) { - ui::PopupInfo::open("hex.yara_rules.view.yara.rule_added"_lang); + ui::ToastInfo::open("hex.yara_rules.view.yara.rule_added"_lang); return true; } }