1
0
mirror of synced 2025-01-29 19:17:28 +01:00

impr: Switch most usages of modals over to toasts

This commit is contained in:
WerWolv 2023-12-26 00:22:47 +01:00
parent 52192a3b26
commit 96fe608d60
25 changed files with 129 additions and 121 deletions

@ -1 +1 @@
Subproject commit b998f3d47940970d0ff74451ea6a7ca06c803af5 Subproject commit 5b54c3b814c784500fb40fb6cfe55f8aa7187fcb

View File

@ -289,11 +289,6 @@ namespace hex {
EVENT_DEF(RequestCreateProvider, std::string, bool, bool, hex::prv::Provider **); EVENT_DEF(RequestCreateProvider, std::string, bool, bool, hex::prv::Provider **);
EVENT_DEF(RequestInitThemeHandlers); 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 * @brief Send an event to the main Imhex instance
*/ */

View File

@ -672,7 +672,6 @@ namespace hex {
// Draw popup stack // Draw popup stack
{ {
static bool popupDisplaying = false;
static bool positionSet = false; static bool positionSet = false;
static bool sizeSet = false; static bool sizeSet = false;
static double popupDelay = -2.0; static double popupDelay = -2.0;
@ -724,7 +723,6 @@ namespace hex {
const auto createPopup = [&](bool displaying) { const auto createPopup = [&](bool displaying) {
if (displaying) { if (displaying) {
currPopup->drawContent(); currPopup->drawContent();
popupDisplaying = true;
if (ImGui::GetWindowSize().x > ImGui::GetStyle().FramePadding.x * 10) if (ImGui::GetWindowSize().x > ImGui::GetStyle().FramePadding.x * 10)
sizeSet = true; sizeSet = true;
@ -742,8 +740,6 @@ namespace hex {
} }
ImGui::EndPopup(); ImGui::EndPopup();
} else {
popupDisplaying = false;
} }
}; };
@ -752,7 +748,7 @@ namespace hex {
else else
createPopup(ImGui::BeginPopup(name, flags)); createPopup(ImGui::BeginPopup(name, flags));
if (!popupDisplaying || currPopup->shouldClose()) { if (currPopup->shouldClose()) {
log::debug("Closing popup '{}'", name); log::debug("Closing popup '{}'", name);
positionSet = sizeSet = false; positionSet = sizeSet = false;
@ -763,41 +759,38 @@ namespace hex {
// Draw Toasts // Draw Toasts
{ {
static std::unique_ptr<impl::ToastBase> currToast; u32 index = 0;
if (currToast == nullptr) { for (const auto &toast : impl::ToastBase::getQueuedToasts() | std::views::take(4)) {
if (auto &queuedToasts = impl::ToastBase::getQueuedToasts(); !queuedToasts.empty()) { const auto toastHeight = 60_scaled;
currToast = std::move(queuedToasts.front());
queuedToasts.pop_front();
currToast->setAppearTime(ImGui::GetTime());
}
} else {
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5_scaled); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5_scaled);
ImGui::SetNextWindowSize(scaled({ 280, 60 })); ImGui::SetNextWindowSize(ImVec2(280_scaled, toastHeight));
ImGui::SetNextWindowPos((ImHexApi::System::getMainWindowPosition() + ImHexApi::System::getMainWindowSize()) - scaled({ 10, 10 }), ImGuiCond_Always, ImVec2(1, 1)); ImGui::SetNextWindowPos((ImHexApi::System::getMainWindowPosition() + ImHexApi::System::getMainWindowSize()) - scaled({ 10, 10 }) - scaled({ 0, (10 + toastHeight) * index }), 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)) { 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(); auto drawList = ImGui::GetWindowDrawList();
const auto min = ImGui::GetWindowPos(); const auto min = ImGui::GetWindowPos();
const auto max = min + ImGui::GetWindowSize(); const auto max = min + ImGui::GetWindowSize();
drawList->PushClipRect(min, min + scaled({ 5, 60 })); 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(); drawList->PopClipRect();
ImGui::Indent(); ImGui::Indent();
currToast->draw(); toast->draw();
ImGui::Unindent(); ImGui::Unindent();
if (ImGui::IsWindowHovered() || toast->getAppearTime() <= 0)
toast->setAppearTime(ImGui::GetTime());
} }
ImGui::End(); ImGui::End();
ImGui::PopStyleVar(); ImGui::PopStyleVar();
if ((currToast->getAppearTime() + impl::ToastBase::VisibilityTime) < ImGui::GetTime()) { index += 1;
currToast.reset();
}
} }
std::erase_if(impl::ToastBase::getQueuedToasts(), [](const auto &toast){
return toast->getAppearTime() > 0 && (toast->getAppearTime() + impl::ToastBase::VisibilityTime) < ImGui::GetTime();
});
} }
// Run all deferred calls // Run all deferred calls

View File

@ -4,6 +4,7 @@
#include <hex/helpers/crypto.hpp> #include <hex/helpers/crypto.hpp>
#include <toasts/toast_notification.hpp>
#include <popups/popup_notification.hpp> #include <popups/popup_notification.hpp>
#include <popups/popup_text_input.hpp> #include <popups/popup_text_input.hpp>
@ -275,7 +276,7 @@ namespace hex::plugin::builtin {
if (input == password) if (input == password)
achievement.setUnlocked(true); achievement.setUnlocked(true);
else else
ui::PopupInfo::open("The password you entered was incorrect."); ui::ToastWarning::open("The password you entered was incorrect.");
}); });
}); });

View File

@ -14,6 +14,7 @@
#include <wolv/io/fs.hpp> #include <wolv/io/fs.hpp>
#include <wolv/utils/string.hpp> #include <wolv/utils/string.hpp>
#include <toasts/toast_notification.hpp>
#include <popups/popup_notification.hpp> #include <popups/popup_notification.hpp>
#include <popups/popup_question.hpp> #include <popups/popup_question.hpp>
#include <content/popups/popup_tasks_waiting.hpp> #include <content/popups/popup_tasks_waiting.hpp>
@ -26,7 +27,7 @@ namespace hex::plugin::builtin {
if (auto *fileProvider = dynamic_cast<FileProvider*>(provider); fileProvider != nullptr) { if (auto *fileProvider = dynamic_cast<FileProvider*>(provider); fileProvider != nullptr) {
fileProvider->setPath(path); fileProvider->setPath(path);
if (!provider->open() || !provider->isAvailable()) { 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); }); TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
} else { } else {
EventProviderOpened::post(fileProvider); EventProviderOpened::post(fileProvider);
@ -104,7 +105,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Open, { }, [](const auto &path) { fs::openFileBrowser(fs::DialogMode::Open, { }, [](const auto &path) {
if (path.extension() == ".hexproj") { if (path.extension() == ".hexproj") {
if (!ProjectFile::load(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)));
} }
} else { } else {
FileProvider* newProvider = static_cast<FileProvider*>( FileProvider* newProvider = static_cast<FileProvider*>(
@ -128,7 +129,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} }, fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} },
[](const auto &path) { [](const auto &path) {
if (!ProjectFile::load(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; return;
} }
if (!provider->open()) { 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); }); TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
return; return;
} }
@ -158,7 +159,7 @@ namespace hex::plugin::builtin {
} }
else if (!provider->hasLoadInterface()) { else if (!provider->hasLoadInterface()) {
if (!provider->open() || !provider->isAvailable()) { 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); }); TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
return; return;
} }
@ -171,18 +172,6 @@ namespace hex::plugin::builtin {
ImHexApi::HexEditor::impl::setCurrentSelection(region); 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){ fs::setFileBrowserErrorCallback([](const std::string& errMsg){
#if defined(NFD_PORTAL) #if defined(NFD_PORTAL)
ui::PopupError::open(hex::format("hex.builtin.popup.error.file_dialog.portal"_lang, errMsg)); ui::PopupError::open(hex::format("hex.builtin.popup.error.file_dialog.portal"_lang, errMsg));

View File

@ -3,7 +3,7 @@
#include <hex/api/project_file_manager.hpp> #include <hex/api/project_file_manager.hpp>
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <popups/popup_notification.hpp> #include <toasts/toast_notification.hpp>
#include <wolv/utils/string.hpp> #include <wolv/utils/string.hpp>
@ -13,7 +13,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} }, fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} },
[](const auto &path) { [](const auto &path) {
if (!ProjectFile::load(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() { void saveProject() {
if (ImHexApi::Provider::isValid() && ProjectFile::hasPath()) { if (ImHexApi::Provider::isValid() && ProjectFile::hasPath()) {
if (!ProjectFile::store()) { if (!ProjectFile::store()) {
ui::PopupError::open("hex.builtin.popup.error.project.save"_lang); ui::ToastError::open("hex.builtin.popup.error.project.save"_lang);
} else { } else {
log::debug("Project saved"); log::debug("Project saved");
} }
@ -36,7 +36,7 @@ namespace hex::plugin::builtin {
} }
if (!ProjectFile::store(path)) { if (!ProjectFile::store(path)) {
ui::PopupError::open("hex.builtin.popup.error.project.save"_lang); ui::ToastError::open("hex.builtin.popup.error.project.save"_lang);
} }
}); });
} }

View File

@ -1,16 +1,16 @@
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <popups/popup_notification.hpp> #include <toasts/toast_notification.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
void showError(const std::string& message){ void showError(const std::string& message){
ui::PopupError::open(message); ui::ToastError::open(message);
log::error(message); log::error(message);
} }
void showWarning(const std::string& message){ void showWarning(const std::string& message){
ui::PopupWarning::open(message); ui::ToastWarning::open(message);
log::warn(message); log::warn(message);
} }
} }

View File

@ -14,7 +14,7 @@
#include <hex/helpers/debugging.hpp> #include <hex/helpers/debugging.hpp>
#include <content/global_actions.hpp> #include <content/global_actions.hpp>
#include <popups/popup_notification.hpp> #include <toasts/toast_notification.hpp>
#include <popups/popup_text_input.hpp> #include <popups/popup_text_input.hpp>
#include <hex/api/workspace_manager.hpp> #include <hex/api/workspace_manager.hpp>
@ -50,19 +50,19 @@ namespace hex::plugin::builtin {
TaskManager::doLater([error]{ TaskManager::doLater([error]{
switch (error) { switch (error) {
case IPSError::InvalidPatchHeader: 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; break;
case IPSError::AddressOutOfRange: 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; break;
case IPSError::PatchTooLarge: 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; break;
case IPSError::InvalidPatchFormat: 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; break;
case IPSError::MissingEOF: 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; break;
} }
}); });
@ -77,7 +77,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) { fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
wolv::io::File inputFile(path, wolv::io::File::Mode::Read); wolv::io::File inputFile(path, wolv::io::File::Mode::Read);
if (!inputFile.isValid()) { 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; return;
} }
@ -87,19 +87,19 @@ namespace hex::plugin::builtin {
auto data = crypt::decode64(base64); auto data = crypt::decode64(base64);
if (data.empty()) 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 { else {
fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const std::fs::path &path) { fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const std::fs::path &path) {
wolv::io::File outputFile(path, wolv::io::File::Mode::Create); wolv::io::File outputFile(path, wolv::io::File::Mode::Create);
if (!outputFile.isValid()) 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); outputFile.writeVector(data);
}); });
} }
} else { } 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(); auto patchData = wolv::io::File(path, wolv::io::File::Mode::Read).readVector();
if (patchData.size() != provider->getActualSize()) { 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; return;
} }
@ -203,7 +203,7 @@ namespace hex::plugin::builtin {
wolv::io::File outputFile(path, wolv::io::File::Mode::Create); wolv::io::File outputFile(path, wolv::io::File::Mode::Create);
if (!outputFile.isValid()) { if (!outputFile.isValid()) {
TaskManager::doLater([] { 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; return;
} }
@ -238,7 +238,7 @@ namespace hex::plugin::builtin {
wolv::io::File file(path, wolv::io::File::Mode::Create); wolv::io::File file(path, wolv::io::File::Mode::Create);
if (!file.isValid()) { if (!file.isValid()) {
TaskManager::doLater([] { 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; return;
} }
@ -269,7 +269,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Save, { { "Markdown File", "md" }}, [&data](const auto &path) { fs::openFileBrowser(fs::DialogMode::Save, { { "Markdown File", "md" }}, [&data](const auto &path) {
auto file = wolv::io::File(path, wolv::io::File::Mode::Create); auto file = wolv::io::File(path, wolv::io::File::Mode::Create);
if (!file.isValid()) { 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; return;
} }
@ -302,7 +302,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) { fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) {
auto file = wolv::io::File(path, wolv::io::File::Mode::Create); auto file = wolv::io::File(path, wolv::io::File::Mode::Create);
if (!file.isValid()) { 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; return;
} }
@ -341,7 +341,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) { fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) {
auto file = wolv::io::File(path, wolv::io::File::Mode::Create); auto file = wolv::io::File(path, wolv::io::File::Mode::Create);
if (!file.isValid()) { 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; return;
} }

View File

@ -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_diskHandle = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
m_writable = false; m_writable = false;
if (m_diskHandle == INVALID_HANDLE_VALUE) if (m_diskHandle == INVALID_HANDLE_VALUE) {
this->setErrorMessage(std::system_category().message(::GetLastError()));
return false; return false;
}
} }
{ {
@ -178,6 +180,7 @@ namespace hex::plugin::builtin {
} }
if (m_diskHandle == nullptr || m_diskHandle == INVALID_HANDLE_VALUE) { if (m_diskHandle == nullptr || m_diskHandle == INVALID_HANDLE_VALUE) {
this->setErrorMessage(std::system_category().message(::GetLastError()));
m_readable = false; m_readable = false;
m_diskHandle = nullptr; m_diskHandle = nullptr;
CloseHandle(m_diskHandle); CloseHandle(m_diskHandle);
@ -220,9 +223,9 @@ namespace hex::plugin::builtin {
#if defined(OS_WINDOWS) #if defined(OS_WINDOWS)
if (m_diskHandle != INVALID_HANDLE_VALUE) if (m_diskHandle != INVALID_HANDLE_VALUE)
::CloseHandle(m_diskHandle); ::CloseHandle(m_diskHandle);
m_diskHandle = INVALID_HANDLE_VALUE; m_diskHandle = INVALID_HANDLE_VALUE;
#else #else

View File

@ -16,6 +16,8 @@
#include <hex/helpers/fmt.hpp> #include <hex/helpers/fmt.hpp>
#include <hex/ui/view.hpp> #include <hex/ui/view.hpp>
#include <toasts/toast_notification.hpp>
#include <wolv/io/fs.hpp> #include <wolv/io/fs.hpp>
#include <wolv/io/file.hpp> #include <wolv/io/file.hpp>
#include <wolv/utils/guards.hpp> #include <wolv/utils/guards.hpp>
@ -294,7 +296,7 @@ namespace hex::plugin::builtin {
if (loadLibraryW != nullptr) { if (loadLibraryW != nullptr) {
if (auto threadHandle = CreateRemoteThread(m_processHandle, nullptr, 0, loadLibraryW, pathAddress, 0, nullptr); threadHandle != nullptr) { if (auto threadHandle = CreateRemoteThread(m_processHandle, nullptr, 0, loadLibraryW, pathAddress, 0, nullptr); threadHandle != nullptr) {
WaitForSingleObject(threadHandle, INFINITE); 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(); this->reloadProcessModules();
CloseHandle(threadHandle); CloseHandle(threadHandle);
return; 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 #endif

View File

@ -15,7 +15,7 @@
#include <wolv/utils/string.hpp> #include <wolv/utils/string.hpp>
#include <content/recent.hpp> #include <content/recent.hpp>
#include <popups/popup_notification.hpp> #include <toasts/toast_notification.hpp>
#include <fonts/codicons_font.h> #include <fonts/codicons_font.h>
namespace hex::plugin::builtin::recent { namespace hex::plugin::builtin::recent {
@ -224,7 +224,7 @@ namespace hex::plugin::builtin::recent {
provider->loadSettings(recentEntry.data); provider->loadSettings(recentEntry.data);
if (!provider->open() || !provider->isAvailable()) { 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); }); TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
return; return;
} }

View File

@ -2,6 +2,7 @@
#include <hex/helpers/fmt.hpp> #include <hex/helpers/fmt.hpp>
#include <hex/helpers/fs.hpp> #include <hex/helpers/fs.hpp>
#include <hex/api/localization_manager.hpp> #include <hex/api/localization_manager.hpp>
#include <hex/api/task_manager.hpp>
#include <algorithm> #include <algorithm>
#include <random> #include <random>
@ -9,7 +10,7 @@
#include <imgui.h> #include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h> #include <hex/ui/imgui_imhex_extensions.h>
#include <popups/popup_notification.hpp> #include <toasts/toast_notification.hpp>
#include <wolv/io/file.hpp> #include <wolv/io/file.hpp>
@ -113,7 +114,7 @@ namespace hex::plugin::builtin {
wolv::io::File output(outputPath, wolv::io::File::Mode::Create); wolv::io::File output(outputPath, wolv::io::File::Mode::Create);
if (!output.isValid()) { 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; return;
} }
@ -126,7 +127,7 @@ namespace hex::plugin::builtin {
wolv::io::File input(file, wolv::io::File::Mode::Read); wolv::io::File input(file, wolv::io::File::Mode::Read);
if (!input.isValid()) { 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; return;
} }
@ -142,7 +143,7 @@ namespace hex::plugin::builtin {
selectedIndex = 0; selectedIndex = 0;
outputPath.clear(); outputPath.clear();
ui::PopupInfo::open("hex.builtin.tools.file_tools.combiner.success"_lang); ui::ToastInfo::open("hex.builtin.tools.file_tools.combiner.success"_lang);
}); });
} }
} }

View File

@ -1,5 +1,6 @@
#include <hex/helpers/fs.hpp> #include <hex/helpers/fs.hpp>
#include <hex/api/localization_manager.hpp> #include <hex/api/localization_manager.hpp>
#include <hex/api/task_manager.hpp>
#include <algorithm> #include <algorithm>
#include <random> #include <random>
@ -7,7 +8,7 @@
#include <imgui.h> #include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h> #include <hex/ui/imgui_imhex_extensions.h>
#include <popups/popup_notification.hpp> #include <toasts/toast_notification.hpp>
#include <wolv/io/file.hpp> #include <wolv/io/file.hpp>
#include <wolv/utils/guards.hpp> #include <wolv/utils/guards.hpp>
@ -54,7 +55,7 @@ namespace hex::plugin::builtin {
wolv::io::File file(selectedFile, wolv::io::File::Mode::Write); wolv::io::File file(selectedFile, wolv::io::File::Mode::Write);
if (!file.isValid()) { 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; return;
} }
@ -128,7 +129,7 @@ namespace hex::plugin::builtin {
file.remove(); file.remove();
ui::PopupInfo::open("hex.builtin.tools.file_tools.shredder.success"_lang); ui::ToastInfo::open("hex.builtin.tools.file_tools.shredder.success"_lang);
}); });
} }
} }

View File

@ -3,13 +3,14 @@
#include <hex/helpers/literals.hpp> #include <hex/helpers/literals.hpp>
#include <hex/helpers/fs.hpp> #include <hex/helpers/fs.hpp>
#include <hex/api/localization_manager.hpp> #include <hex/api/localization_manager.hpp>
#include <hex/api/task_manager.hpp>
#include <algorithm> #include <algorithm>
#include <imgui.h> #include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h> #include <hex/ui/imgui_imhex_extensions.h>
#include <popups/popup_notification.hpp> #include <toasts/toast_notification.hpp>
#include <wolv/io/file.hpp> #include <wolv/io/file.hpp>
#include <wolv/utils/guards.hpp> #include <wolv/utils/guards.hpp>
@ -101,12 +102,12 @@ namespace hex::plugin::builtin {
wolv::io::File file(selectedFile, wolv::io::File::Mode::Read); wolv::io::File file(selectedFile, wolv::io::File::Mode::Read);
if (!file.isValid()) { 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; return;
} }
if (file.getSize() < splitSize) { 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; return;
} }
@ -122,7 +123,7 @@ namespace hex::plugin::builtin {
wolv::io::File partFile(path, wolv::io::File::Mode::Create); wolv::io::File partFile(path, wolv::io::File::Mode::Create);
if (!partFile.isValid()) { 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; return;
} }
@ -135,7 +136,7 @@ namespace hex::plugin::builtin {
index++; 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);
}); });
} }
} }

View File

@ -1,6 +1,7 @@
#include <hex/api/content_registry.hpp> #include <hex/api/content_registry.hpp>
#include <hex/api/imhex_api.hpp> #include <hex/api/imhex_api.hpp>
#include <hex/api/localization_manager.hpp> #include <hex/api/localization_manager.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/ui/view.hpp> #include <hex/ui/view.hpp>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
@ -13,7 +14,7 @@
#include <implot.h> #include <implot.h>
#include <hex/ui/imgui_imhex_extensions.h> #include <hex/ui/imgui_imhex_extensions.h>
#include <popups/popup_notification.hpp> #include <toasts/toast_notification.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@ -43,10 +44,10 @@ namespace hex::plugin::builtin {
} }
static void drawGlobalPopups() { static void drawGlobalPopups() {
// Task exception popup // Task exception toast
for (const auto &task : TaskManager::getRunningTasks()) { for (const auto &task : TaskManager::getRunningTasks()) {
if (task->hadException()) { 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(); task->clearException();
break; break;
} }

View File

@ -1,5 +1,5 @@
#include "content/views/view_data_processor.hpp" #include "content/views/view_data_processor.hpp"
#include <popups/popup_notification.hpp> #include <toasts/toast_notification.hpp>
#include <hex/api/content_registry.hpp> #include <hex/api/content_registry.hpp>
#include <hex/api/project_file_manager.hpp> #include <hex/api/project_file_manager.hpp>
@ -1194,7 +1194,7 @@ namespace hex::plugin::builtin {
m_updateNodePositions = true; m_updateNodePositions = true;
} catch (nlohmann::json::exception &e) { } 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()));
} }
} }

View File

@ -14,7 +14,7 @@
#include <implot.h> #include <implot.h>
#include <popups/popup_notification.hpp> #include <toasts/toast_notification.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@ -48,7 +48,7 @@ namespace hex::plugin::builtin {
ContentRegistry::FileHandler::add({ ".mgc" }, [](const auto &path) { ContentRegistry::FileHandler::add({ ".mgc" }, [](const auto &path) {
for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Magic)) { for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
if (wolv::io::fs::copyFile(path, destPath / path.filename(), std::fs::copy_options::overwrite_existing)) { 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; return true;
} }
} }

View File

@ -1,7 +1,9 @@
#include "content/views/view_provider_settings.hpp" #include "content/views/view_provider_settings.hpp"
#include <popups/popup_notification.hpp>
#include <hex/api/content_registry.hpp> #include <hex/api/content_registry.hpp>
#include <hex/api/task_manager.hpp>
#include <toasts/toast_notification.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@ -49,9 +51,9 @@ namespace hex::plugin::builtin {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
auto errorMessage = provider->getErrorMessage(); auto errorMessage = provider->getErrorMessage();
if (errorMessage.empty()) { 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 { } 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); }); TaskManager::doLater([=] { ImHexApi::Provider::remove(provider); });
} }

View File

@ -6,6 +6,7 @@
#include <hex/api/content_registry.hpp> #include <hex/api/content_registry.hpp>
#include <popups/popup_notification.hpp> #include <popups/popup_notification.hpp>
#include <toasts/toast_notification.hpp>
#include <imgui.h> #include <imgui.h>
@ -310,7 +311,7 @@ namespace hex::plugin::builtin {
} }
if (!downloading) { if (!downloading) {
ui::PopupError::open("hex.builtin.view.store.download_error"_lang); ui::ToastError::open("hex.builtin.view.store.download_error"_lang);
return false; return false;
} }

View File

@ -12,6 +12,9 @@ add_imhex_plugin(
INCLUDES INCLUDES
include include
LIBRARIES
ui
) )
if (CoreClrEmbed_FOUND) if (CoreClrEmbed_FOUND)

View File

@ -8,6 +8,8 @@
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <popups/popup_notification.hpp>
using namespace hex; using namespace hex;
#define VERSION V1 #define VERSION V1
@ -114,7 +116,7 @@ private:
}; };
SCRIPT_API(void showMessageBox, const char *message) { 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) { SCRIPT_API(void showInputTextBox, const char *title, const char *message, char *buffer, u32 bufferSize) {

View File

@ -7,49 +7,59 @@
#include <fonts/codicons_font.h> #include <fonts/codicons_font.h>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <popups/popup_notification.hpp>
namespace hex::ui { namespace hex::ui {
namespace impl { namespace impl {
template<typename T> template<typename T>
struct ToastNotification : Toast<T> { struct ToastNotification : Toast<T> {
ToastNotification(ImColor color, const char *icon, UnlocalizedString title, UnlocalizedString message) ToastNotification(ImColor color, const char *icon, UnlocalizedString unlocalizedTitle, std::string message)
: Toast<T>(color), m_icon(icon), m_title(std::move(title)), m_message(std::move(message)) {} : Toast<T>(color), m_icon(icon), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_message(std::move(message)) {}
void drawContent() final { 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); ImGuiExt::TextFormattedColored(this->getColor(), "{}", m_icon);
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushFont(ImHexApi::Fonts::Bold());
{ ImGuiExt::TextFormatted("{}", hex::limitStringLength(Lang(m_unlocalizedTitle).get(), 30));
ImGuiExt::TextFormatted("{}", hex::limitStringLength(Lang(m_title).get(), 30));
}
ImGui::PopFont();
ImGui::Separator(); ImGui::Separator();
ImGuiExt::TextFormattedWrapped("{}", hex::limitStringLength(Lang(m_message).get(), 60)); ImGuiExt::TextFormattedWrapped("{}", hex::limitStringLength(m_message, 60));
} }
private: private:
const char *m_icon; const char *m_icon;
UnlocalizedString m_title, m_message; UnlocalizedString m_unlocalizedTitle;
std::string m_message;
}; };
} }
struct ToastInfo : impl::ToastNotification<ToastInfo> { struct ToastInfo : impl::ToastNotification<ToastInfo> {
ToastInfo(UnlocalizedString title, UnlocalizedString message) ToastInfo(std::string message)
: ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerInfo), ICON_VS_INFO, std::move(title), std::move(message)) {} : ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerInfo), ICON_VS_INFO, "hex.ui.common.info", std::move(message)) {}
}; };
struct ToastWarn : impl::ToastNotification<ToastWarn> { struct ToastWarning : impl::ToastNotification<ToastWarning> {
ToastWarn(UnlocalizedString title, UnlocalizedString message) ToastWarning(std::string message)
: ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerWarning), ICON_VS_WARNING, std::move(title), std::move(message)) {} : ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerWarning), ICON_VS_WARNING, "hex.ui.common.warning", std::move(message)) {}
}; };
struct ToastError : impl::ToastNotification<ToastError> { struct ToastError : impl::ToastNotification<ToastError> {
ToastError(UnlocalizedString title, UnlocalizedString message) ToastError(std::string message)
: ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerError), ICON_VS_ERROR, std::move(title), std::move(message)) {} : ToastNotification(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_LoggerError), ICON_VS_ERROR, "hex.ui.common.error", std::move(message)) {}
}; };
} }

View File

@ -16,6 +16,7 @@ if (WIN32)
INCLUDES INCLUDES
include include
LIBRARIES LIBRARIES
ui
${JTHREAD_LIBRARIES} ${JTHREAD_LIBRARIES}
) )

View File

@ -5,6 +5,8 @@
#include <hex/api/task_manager.hpp> #include <hex/api/task_manager.hpp>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <toasts/toast_notification.hpp>
#include <wolv/utils/guards.hpp> #include <wolv/utils/guards.hpp>
#include <windows.h> #include <windows.h>
@ -85,7 +87,7 @@ namespace hex::plugin::windows {
if (m_portHandle == INVALID_HANDLE_VALUE) { if (m_portHandle == INVALID_HANDLE_VALUE) {
if (ImGui::Button("hex.windows.view.tty_console.connect"_lang)) if (ImGui::Button("hex.windows.view.tty_console.connect"_lang))
if (!this->connect()) 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 { } else {
if (ImGui::Button("hex.windows.view.tty_console.disconnect"_lang)) if (ImGui::Button("hex.windows.view.tty_console.disconnect"_lang))
this->disconnect(); this->disconnect();
@ -184,7 +186,7 @@ namespace hex::plugin::windows {
bool ViewTTYConsole::connect() { bool ViewTTYConsole::connect() {
if (m_comPorts.empty() || static_cast<size_t>(m_selectedPort) >= m_comPorts.size()) { if (m_comPorts.empty() || static_cast<size_t>(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 return true; // If false, connect_error error popup will override this error popup
} }
m_portHandle = ::CreateFile((R"(\\.\)" + m_comPorts[m_selectedPort].first).c_str(), m_portHandle = ::CreateFile((R"(\\.\)" + m_comPorts[m_selectedPort].first).c_str(),

View File

@ -6,7 +6,7 @@
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <hex/helpers/fs.hpp> #include <hex/helpers/fs.hpp>
#include <popups/popup_notification.hpp> #include <toasts/toast_notification.hpp>
#include <popups/popup_file_chooser.hpp> #include <popups/popup_file_chooser.hpp>
// <yara/types.h>'s RE type has a zero-sized array, which is not allowed in ISO C++. // <yara/types.h>'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) { ContentRegistry::FileHandler::add({ ".yar", ".yara" }, [](const auto &path) {
for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Yara)) { for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Yara)) {
if (wolv::io::fs::copyFile(path, destPath / path.filename(), std::fs::copy_options::overwrite_existing)) { 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; return true;
} }
} }