feat: Added banners, replace some modals with them

This commit is contained in:
WerWolv
2025-01-15 17:54:07 +01:00
parent d504937d50
commit cb11b57ab1
10 changed files with 206 additions and 16 deletions

View File

@@ -50,6 +50,7 @@ set(LIBIMHEX_SOURCES
source/ui/view.cpp
source/ui/popup.cpp
source/ui/toast.cpp
source/ui/banner.cpp
source/subcommands/subcommands.cpp
)

View File

@@ -0,0 +1,57 @@
#pragma once
#include <hex.hpp>
#include <imgui.h>
#include <imgui_internal.h>
#include <hex/helpers/utils.hpp>
#include <list>
#include <memory>
#include <mutex>
#include "hex/api/localization_manager.hpp"
namespace hex {
namespace impl {
class BannerBase {
public:
BannerBase(ImColor color) : m_color(color) {}
virtual ~BannerBase() = default;
virtual void draw() { drawContent(); }
virtual void drawContent() = 0;
[[nodiscard]] static std::list<std::unique_ptr<BannerBase>> &getOpenBanners();
[[nodiscard]] const ImColor& getColor() const {
return m_color;
}
void close() { m_shouldClose = true; }
[[nodiscard]] bool shouldClose() const { return m_shouldClose; }
protected:
static std::mutex& getMutex();
bool m_shouldClose = false;
ImColor m_color;
};
}
template<typename T>
class Banner : public impl::BannerBase {
public:
using impl::BannerBase::BannerBase;
template<typename ...Args>
static void open(Args && ... args) {
std::lock_guard lock(getMutex());
auto toast = std::make_unique<T>(std::forward<Args>(args)...);
getOpenBanners().emplace_back(std::move(toast));
}
};
}

View File

@@ -686,7 +686,7 @@ namespace hex {
return string;
// If the string is longer than the max length, find the last space before the max length
auto it = string.begin() + maxLength;
auto it = string.begin() + maxLength / 2;
while (it != string.begin() && !std::isspace(*it)) --it;
// If there's no space before the max length, just cut the string

View File

@@ -0,0 +1,18 @@
#include <hex/ui/banner.hpp>
#include <hex/helpers/auto_reset.hpp>
namespace hex::impl {
[[nodiscard]] std::list<std::unique_ptr<BannerBase>> &BannerBase::getOpenBanners() {
static AutoReset<std::list<std::unique_ptr<BannerBase>>> openBanners;
return openBanners;
}
std::mutex& BannerBase::getMutex() {
static std::mutex mutex;
return mutex;
}
}

View File

@@ -25,6 +25,8 @@ namespace hex::init {
int main(int argc, char **argv) {
using namespace hex;
std::setlocale(LC_ALL, "en_US.utf8");
// Set the main thread's name to "Main"
TaskManager::setCurrentThreadName("Main");
@@ -43,9 +45,10 @@ int main(int argc, char **argv) {
log::info("Welcome to ImHex {}!", ImHexApi::System::getImHexVersion().get());
log::info("Compiled using commit {}@{}", ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash());
log::info("Running on {} {} ({})", ImHexApi::System::getOSName(), ImHexApi::System::getOSVersion(), ImHexApi::System::getArchitecture());
#if defined(OS_LINUX)
auto distro = ImHexApi::System::getLinuxDistro().value();
log::info("Linux distribution: {}. Version: {}", distro.name, distro.version == "" ? "None" : distro.version);
auto distro = ImHexApi::System::getLinuxDistro().value();
log::info("Linux distribution: {}. Version: {}", distro.name, distro.version == "" ? "None" : distro.version);
#endif

View File

@@ -1,4 +1,5 @@
#include "window.hpp"
#include "hex/ui/banner.hpp"
#include <hex.hpp>
@@ -553,6 +554,44 @@ namespace hex {
});
}
// Draw Banners
{
const bool onWelcomeScreen = !ImHexApi::Provider::isValid();
float startY = (ImGui::GetTextLineHeight() + ImGui::GetStyle().FramePadding.y * 2.0F) * (onWelcomeScreen ? 2 : 3);
const auto height = 30_scaled;
for (const auto &banner : impl::BannerBase::getOpenBanners() | std::views::take(5)) {
ImGui::PushID(banner.get());
{
ImGui::SetNextWindowPos(ImVec2(1_scaled, startY));
ImGui::SetNextWindowSize(ImVec2(ImHexApi::System::getMainWindowSize().x - 2_scaled, height));
ImGui::PushStyleColor(ImGuiCol_WindowBg, banner->getColor().Value);
if (ImGui::Begin("##Banner", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing)) {
if (ImGui::BeginChild("##Content", ImGui::GetContentRegionAvail() - ImVec2(20_scaled, 0))) {
banner->draw();
}
ImGui::EndChild();
ImGui::SameLine();
if (ImGui::CloseButton(ImGui::GetID("BannerCloseButton"), ImGui::GetCursorScreenPos())) {
banner->close();
}
}
ImGui::End();
ImGui::PopStyleColor();
}
ImGui::PopID();
startY += height;
}
std::erase_if(impl::BannerBase::getOpenBanners(), [](const auto &banner) {
return banner->shouldClose();
});
}
// Run all deferred calls
TaskManager::runDeferredCalls();
}

View File

@@ -422,8 +422,10 @@
"hex.builtin.provider.file.size": "Size",
"hex.builtin.provider.file.menu.open_file": "Open file externally",
"hex.builtin.provider.file.menu.open_folder": "Open containing folder",
"hex.builtin.provider.file.too_large": "This file is too large to be loaded into memory. Opening it anyways will result in modifications to be written directly to the file. Would you like to open it as Read-Only instead?",
"hex.builtin.provider.file.reload_changes": "The file has been modified by an external source. Do you want to reload it?",
"hex.builtin.provider.file.too_large": "File is larger than limit set limit, changes will be written directly to the file. Allow write access anyways?",
"hex.builtin.provider.file.too_large.allow_write": "Allow write access",
"hex.builtin.provider.file.reload_changes": "File has been modified by an external source. Do you want to reload it?",
"hex.builtin.provider.file.reload_changes.reload": "Reload",
"hex.builtin.provider.gdb": "GDB Server Data",
"hex.builtin.provider.gdb.ip": "IP Address",
"hex.builtin.provider.gdb.name": "GDB Server <{0}:{1}>",

View File

@@ -7,7 +7,7 @@
#include <hex/api/project_file_manager.hpp>
#include <hex/api/task_manager.hpp>
#include <popups/popup_question.hpp>
#include <banners/banner_button.hpp>
#include <toasts/toast_notification.hpp>
#include <hex/helpers/utils.hpp>
@@ -216,11 +216,7 @@ namespace hex::plugin::builtin {
if (result && directAccess) {
m_writable = false;
ui::PopupQuestion::open("hex.builtin.provider.file.too_large"_lang,
[this] {
m_writable = false;
},
[this] {
ui::BannerButton::open(ICON_VS_WARNING, "hex.builtin.provider.file.too_large", ImColor(135, 116, 66), "hex.builtin.provider.file.too_large.allow_write", [this]{
m_writable = true;
RequestUpdateWindowTitle::post();
});
@@ -281,6 +277,8 @@ namespace hex::plugin::builtin {
}
}
m_changeEventAcknowledgementPending = false;
return true;
}
@@ -368,15 +366,12 @@ namespace hex::plugin::builtin {
}
m_changeEventAcknowledgementPending = true;
ui::PopupQuestion::open("hex.builtin.provider.file.reload_changes"_lang, [this] {
ui::BannerButton::open(ICON_VS_INFO, "hex.builtin.provider.file.reload_changes"_lang, ImColor(66, 104, 135), "hex.builtin.provider.file.reload_changes.reload", [this] {
this->close();
(void)this->open(!m_loadedIntoMemory);
getUndoStack().reapply();
m_changeEventAcknowledgementPending = false;
},
[this]{
m_changeEventAcknowledgementPending = false;
});
}

View File

@@ -0,0 +1,51 @@
#pragma once
#include <hex/ui/banner.hpp>
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex::ui {
class BannerButton : public Banner<BannerButton> {
public:
BannerButton(const char *icon, UnlocalizedString message, ImColor color, UnlocalizedString buttonText, std::function<void()> buttonCallback)
: Banner(color), m_icon(icon), m_message(std::move(message)), m_buttonText(std::move(buttonText)), m_buttonCallback(std::move(buttonCallback)) { }
void drawContent() override {
const std::string buttonText = Lang(m_buttonText);
const auto buttonSize = ImGui::CalcTextSize(buttonText.c_str());
ImGui::TextUnformatted(m_icon);
ImGui::SameLine(0, 10_scaled);
const std::string message = Lang(m_message);
const auto messageSize = ImGui::CalcTextSize(message.c_str());
ImGuiExt::TextFormatted("{}", limitStringLength(message, message.size() * ((ImGui::GetContentRegionAvail().x - buttonSize.x - 40_scaled) / messageSize.x)));
if (ImGui::IsItemHovered()) {
ImGui::SetNextWindowSize(ImVec2(400_scaled, 0));
if (ImGui::BeginTooltip()) {
ImGuiExt::TextFormattedWrapped("{}", message);
ImGui::EndTooltip();
}
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - buttonSize.x - 20_scaled);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2_scaled);
if (ImGui::SmallButton(buttonText.c_str())) {
m_buttonCallback();
this->close();
}
ImGui::PopStyleVar(1);
}
private:
const char *m_icon;
UnlocalizedString m_message;
UnlocalizedString m_buttonText;
std::function<void()> m_buttonCallback;
};
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include <hex/ui/banner.hpp>
#include <imgui.h>
namespace hex::ui {
class BannerIcon : public Banner<BannerIcon> {
public:
BannerIcon(const char *icon, UnlocalizedString message, ImColor color)
: Banner(color), m_icon(icon), m_message(std::move(message)) { }
void drawContent() override {
ImGui::TextUnformatted(m_icon);
ImGui::SameLine(0, 10_scaled);
ImGui::TextUnformatted(Lang(m_message));
}
private:
const char *m_icon;
UnlocalizedString m_message;
};
}